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 / disp-read.C < prev    next >
C/C++ Source or Header  |  1998-10-23  |  23KB  |  1,001 lines

  1. // $Id: disp-read.C,v 1.96 1998/10/24 01:34:30 zeller Exp $
  2. // Helper functions to process GDB display output
  3.  
  4. // Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
  5. // Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char disp_read_rcsid[] =
  30.     "$Id: disp-read.C,v 1.96 1998/10/24 01:34:30 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. //-----------------------------------------------------------------------------
  37. // Misc routines to process `display' output
  38. //-----------------------------------------------------------------------------
  39.  
  40. #include "assert.h"
  41. #include "disp-read.h"
  42. #include "value-read.h"
  43. #include "string-fun.h"
  44. #include "cook.h"
  45. #include "regexps.h"
  46. #include "AppData.h"
  47.  
  48. #include <stdlib.h>        // atoi()
  49. #include <stdio.h>        // sprintf()
  50. #include <ctype.h>        // isspace()
  51.  
  52.  
  53. //----------------------------------------------------------------------------
  54. // Recognize specific debugger commands
  55. //----------------------------------------------------------------------------
  56.  
  57. // True if CMD creates one signle display
  58. bool is_single_display_cmd (const string& cmd, GDBAgent *gdb)
  59. {
  60. #if RUNTIME_REGEX
  61.     static regex rxsingle_display_cmd(
  62.         "[ \t]*"
  63.     "(disp|displ|displa|display)[ \t]+[^ ]+");
  64. #endif
  65.  
  66.     switch (gdb->type())
  67.     {
  68.     case GDB:
  69.     return cmd.matches (rxsingle_display_cmd);
  70.  
  71.     case DBX:
  72.     case XDB:
  73.     case JDB:
  74.     case PYDB:
  75.     case PERL:
  76.     return false;
  77.     }
  78.  
  79.     return false;
  80. }
  81.  
  82. // True if CMD has no effect on DDD state
  83. bool is_nop_cmd(const string& cmd)
  84. {
  85.     if (app_data.play_log != 0)
  86.     {
  87.     if (cmd.contains('/', 0) ||
  88.         cmd.contains('?', 0) ||
  89.         cmd.contains('.', 0) ||
  90.         cmd.contains('!', 0))
  91.         return true;
  92.     }
  93.  
  94. #if RUNTIME_REGEX
  95.     // All these command have no effect on DDD state...
  96.     static regex rxnop_cmd("[ \t]*(echo|help|show|info|where|shell|sh|x)([ \t]+.*)?");
  97.  
  98.     // ... except for this one.
  99.     static regex rxop_cmd("[ \t]*(info[ \t]+line)([ \t]+.*)?");
  100. #endif
  101.  
  102.     return cmd.matches(rxnop_cmd) && !cmd.matches(rxop_cmd);
  103. }
  104.  
  105. // True if CMD changes program state
  106. bool is_running_cmd (const string& cmd, GDBAgent *gdb)
  107. {
  108. #if RUNTIME_REGEX
  109.     static regex rxrunning_cmd(
  110.     "[ \t]*"
  111.     "(r|ru|run"
  112.     "|rer|rerun"
  113.     "|c|cont|contin|continu|continue"
  114.     "|sig|sign|signa|signal"
  115.     "|u|unt|unti|until"
  116.     "|s|si|step|stepi"
  117.     "|n|ni|next|nexti"
  118.     "|j|ju|jump"
  119.     "|k|ki|kill"
  120.     "|fin|fini|finis|finish"
  121.         "|R|S"
  122.     ")([ \t]+.*)?");
  123.  
  124.     static regex rxdisplay("[ \t]*(disp|displ|displa|display)([ \t]+.*)?");
  125. #endif
  126.  
  127.     switch (gdb->type())
  128.     {
  129.     case GDB:
  130.     return cmd.matches(rxrunning_cmd)
  131.         || cmd.matches(rxdisplay)
  132.         || is_display_cmd(cmd);
  133.  
  134.     case DBX:
  135.     case XDB:
  136.     case JDB:
  137.     case PYDB:
  138.     case PERL:
  139.     return cmd.matches (rxrunning_cmd)
  140.         || is_display_cmd(cmd);
  141.     }
  142.  
  143.     return false;
  144. }
  145.  
  146. // True if CMD starts program
  147. bool is_run_cmd (const string& cmd)
  148. {
  149. #if RUNTIME_REGEX
  150.     static regex rxrun_cmd("[ \t]*(r|rer|rerun|ru|run|R)([ \t]+.*)?");
  151. #endif
  152.  
  153.     return cmd.matches (rxrun_cmd);
  154. }
  155.  
  156. // True if CMD kills program
  157. bool is_kill_cmd(const string& cmd)
  158. {
  159.     return cmd == "kill" || cmd == "k";
  160. }
  161.  
  162. // True if CMD sets program args
  163. bool is_set_args_cmd (const string& cmd)
  164. {
  165. #if RUNTIME_REGEX
  166.     static regex rxset_args_cmd("[ \t]*set[ \t]+args([ \t]+.*)?");
  167. #endif
  168.  
  169.     return cmd.matches (rxset_args_cmd);
  170. }
  171.  
  172. // True if CMD affects the program counter
  173. bool is_pc_cmd(const string& cmd)
  174. {
  175.     return cmd.contains("$pc");
  176. }
  177.  
  178. // True if CMD creates at least one display
  179. bool is_display_cmd (const string& cmd)
  180. {
  181. #if RUNTIME_REGEX
  182.     static regex rxdisplay_cmd_and_args(
  183.     "[ \t]*(disp|displ|displa|display)[ \t]+.*");
  184. #endif
  185.  
  186.     return cmd.matches (rxdisplay_cmd_and_args);
  187. }
  188.  
  189. // True if CMD changes the list of displays
  190. bool is_data_cmd (const string& cmd)
  191. {
  192.     // enable display, disable display, delete display, undisplay
  193. #if RUNTIME_REGEX
  194.     static regex rxdata("[ \t]*[a-z ]*display([ \t]+.*)?");
  195. #endif
  196.  
  197.     return cmd.matches(rxdata);
  198. }
  199.  
  200. // True if CMD deletes a display
  201. bool is_delete_display_cmd (const string& cmd)
  202. {
  203. #if RUNTIME_REGEX
  204.     static regex rxundisplay("[ \t]*(delete[ \t]+|un)display([ \t]+.*)?");
  205. #endif
  206.  
  207.     return cmd.matches(rxundisplay);
  208. }
  209.  
  210. // True if CMD enables a display
  211. bool is_enable_display_cmd (const string& cmd)
  212. {
  213. #if RUNTIME_REGEX
  214.     static regex rxenable("[ \t]*enable[ \t]+display([ \t]+.*)?");
  215. #endif
  216.  
  217.     return cmd.matches(rxenable);
  218. }
  219.  
  220. // True if CMD disables a display
  221. bool is_disable_display_cmd (const string& cmd)
  222. {
  223. #if RUNTIME_REGEX
  224.     static regex rxdisable("[ \t]*disable[ \t]+display([ \t]+.*)?");
  225. #endif
  226.  
  227.     return cmd.matches(rxdisable);
  228. }
  229.  
  230. // True if CMD changes current frame
  231. bool is_frame_cmd (const string& cmd)
  232. {
  233. #if RUNTIME_REGEX
  234.     static regex rxframe_cmd(
  235.     "[ \t]*"
  236.     "(up"
  237.     "|do|down"
  238.     "|f|fra|fram|frame"
  239.     "|suspend"
  240.     "|resume"
  241.     "|top|V"
  242.     ")([ \t]+.*)?");
  243. #endif
  244.  
  245.     return cmd.matches (rxframe_cmd);
  246. }
  247.  
  248. // True if CMD moves up in stack
  249. bool is_up_cmd (const string& cmd)
  250. {
  251. #if RUNTIME_REGEX
  252.     static regex rxup_cmd("[ \t]*up([ \t]+.*)?");
  253. #endif
  254.  
  255.     return cmd.matches (rxup_cmd);
  256. }
  257.  
  258. // True if CMD moves down in stack
  259. bool is_down_cmd (const string& cmd)
  260. {
  261. #if RUNTIME_REGEX
  262.     static regex rxdown_cmd("[ \t]*(do|down)([ \t]+.*)?");
  263. #endif
  264.  
  265.     return cmd.matches (rxdown_cmd);
  266. }
  267.  
  268. // True if CMD loads a new state (core file or process)
  269. bool is_core_cmd (const string& cmd)
  270. {
  271. #if RUNTIME_REGEX
  272.     static regex rxcore_cmd("[ \t]*(attach|core|core-file)([ \t]+.*)?");
  273. #endif
  274.  
  275.     return cmd.matches (rxcore_cmd);
  276. }
  277.  
  278. // True if CMD changes the current thread
  279. bool is_thread_cmd (const string& cmd)
  280. {
  281. #if RUNTIME_REGEX
  282.     static regex rxthread_cmd("[ \t]*(thread"
  283.                   "|threadgroup"
  284.                   "|suspend"
  285.                   "|resume"
  286.     ")([ \t]+.*)?");
  287. #endif
  288.  
  289.     return cmd.matches (rxthread_cmd);
  290. }
  291.  
  292. // True if CMD changes variables
  293. bool is_assign_cmd(const string& cmd, GDBAgent *gdb)
  294. {
  295. #if RUNTIME_REGEX
  296.     static regex rxset1_cmd("[ \t]*(set[ \t]+var[a-z]*|assign|pq)([ \t]+.*)?");
  297.     static regex rxset2_cmd("[ \t]*(set|p|print|output)[ \t]+[^=]+=[^=].*");
  298.     static regex rxset3_cmd("[ \t]*[^=]+=[^=].*");
  299. #endif
  300.  
  301.     DebuggerType type = gdb->type();
  302.  
  303.     if (type == PERL && cmd.contains("O ", 0))
  304.     return false;        // Setting command
  305.  
  306.     return cmd.matches(rxset1_cmd) || 
  307.     (type == GDB && cmd.matches(rxset2_cmd)) ||
  308.     ((type == PYDB || type == PERL) && cmd.matches(rxset3_cmd));
  309. }
  310.  
  311. // Get assigned variable
  312. string get_assign_variable(const string& _cmd)
  313. {
  314.     string cmd = _cmd;
  315.     strip_space(cmd);
  316.  
  317.     if (cmd.contains(":="))
  318.     cmd = cmd.before(":=");
  319.     else
  320.     cmd = cmd.before('=');    // Remove assignment and assigned value
  321.  
  322.     if (cmd.contains("set var", 0))
  323.     cmd = cmd.after(' ');    // Special case `set variable': two-word cmd
  324.  
  325.     if (cmd.contains(' '))
  326.     cmd = cmd.after(' ');    // Return argument
  327.  
  328.     strip_space(cmd);
  329.     return cmd;
  330. }
  331.  
  332. // True if CMD changes debugger settings
  333. bool is_setting_cmd (const string& cmd)
  334. {
  335. #if RUNTIME_REGEX
  336.     static regex rxsetting_cmd("[ \t]*(set|dbxenv|O)[ \t]+.*");
  337.     static regex rxpath_cmd("[ \t]*(dir|directory|path)([ \t]+.*)?");
  338. #endif
  339.  
  340.     if (is_set_args_cmd(cmd))
  341.     return false;        // `set args' command
  342.  
  343.     return cmd.matches (rxsetting_cmd) || cmd.matches(rxpath_cmd);
  344. }
  345.  
  346. // True if CMD changes debugger signal handling
  347. bool is_handle_cmd (const string& cmd)
  348. {
  349.     return cmd.contains("handle ", 0) && cmd.freq(' ') >= 2;
  350. }
  351.  
  352. // True if CMD changes debugger settings
  353. bool is_define_cmd (const string& cmd)
  354. {
  355. #if RUNTIME_REGEX
  356.     static regex rxdefine_cmd("[ \t]*(define|document)[ \t]+.*");
  357. #endif
  358.  
  359.     return cmd.matches(rxdefine_cmd);
  360. }
  361.  
  362. // True if CMD changes debuggee
  363. bool is_file_cmd (const string& cmd, GDBAgent *gdb)
  364. {
  365.     if (cmd == "# reset")
  366.     return true;
  367.  
  368.     switch (gdb->type())
  369.     {
  370.     case GDB:
  371.     case PYDB:
  372.     {
  373. #if RUNTIME_REGEX
  374.     static regex rxfile_cmd("[ \t]*file([ \t]+.*)?");
  375. #endif
  376.     return cmd.matches (rxfile_cmd);
  377.     }
  378.  
  379.     case DBX:
  380.     {
  381. #if RUNTIME_REGEX
  382.     static regex rxdebug_cmd("[ \t]*(debug|givenfile)([ \t]+.*)?");
  383. #endif
  384.     return cmd.matches (rxdebug_cmd);
  385.     }
  386.  
  387.     case XDB:
  388.     return cmd.contains("#file ", 0);
  389.  
  390.     case JDB:
  391.     return cmd.contains("load ", 0);
  392.  
  393.     case PERL:
  394.     return cmd.contains("exec ", 0);
  395.     }
  396.  
  397.     assert(0);
  398.     return false;
  399. }
  400.  
  401. // True if CMD is a DDD graph command
  402. bool is_graph_cmd (const string& cmd)
  403. {
  404. #if RUNTIME_REGEX
  405.     static regex rxgraph_cmd("[ \t]*graph[ \t]+.*"); 
  406. #endif
  407.  
  408.     return cmd.matches(rxgraph_cmd);
  409. }
  410.  
  411. // True if CMD is a refresh command
  412. bool is_refresh_cmd (const string& cmd)
  413. {
  414. #if RUNTIME_REGEX
  415.     static regex rxrefresh_cmd("[ \t]*refresh([ \t]+.*)?");
  416. #endif
  417.  
  418.     return cmd.matches(rxrefresh_cmd);
  419. }
  420.  
  421. // True if CMD affects breakpoints
  422. bool is_break_cmd (const string& cmd)
  423. {
  424. #if RUNTIME_REGEX
  425.     static regex rxbreak_cmd(
  426.     "[ \t]*"
  427.     "("
  428.     "[th]*(b|br|bre|brea|break|b[a-z])"
  429.     "|cl|cle|clea|clear|d[a-z]"
  430.     "|info[ \t]+(li|lin|line)"
  431.     "|ignore"
  432.     "|cond|condition"
  433.     "|when"
  434.     "|stop"
  435.     ")([ \t]+.*)?");
  436. #endif
  437.  
  438.     return cmd.matches(rxbreak_cmd);
  439. }
  440.  
  441. // True if CMD changes current cursor position
  442. bool is_lookup_cmd (const string& cmd)
  443. {
  444. #if RUNTIME_REGEX
  445.     static regex rxlookup_cmd("[ \t]*(func|v)[ \t]+.*");
  446. #endif
  447.  
  448.     return cmd.matches(rxlookup_cmd);
  449. }
  450.  
  451. // True if CMD changes current cursor position
  452. bool is_list_cmd (const string& cmd)
  453. {
  454. #if RUNTIME_REGEX
  455.     static regex rxlist_cmd("[ \t]*(l|li|lis|list)([ \t]+.*)?");
  456. #endif
  457.  
  458.     return cmd.matches(rxlist_cmd);
  459. }
  460.  
  461. // True if CMD changes directory
  462. bool is_cd_cmd (const string& cmd)
  463. {
  464. #if RUNTIME_REGEX
  465.     static regex rxcd_cmd("[ \t]*cd([ \t]+.*)?");
  466. #endif
  467.  
  468.     return cmd.matches(rxcd_cmd);
  469. }
  470.  
  471. // True if CMD changes class path
  472. bool is_use_cmd (const string& cmd)
  473. {
  474. #if RUNTIME_REGEX
  475.     static regex rxuse_cmd("[ \t]*use[ \t]+.*");
  476. #endif
  477.  
  478.     return cmd.matches(rxuse_cmd);
  479. }
  480.  
  481. // True if CMD invokes `make'
  482. bool is_make_cmd (const string& cmd)
  483. {
  484. #if RUNTIME_REGEX
  485.     static regex rxmake_cmd("[ \t]*(sh[ \t]+|!)?make([ \t]+.*)?");
  486. #endif
  487.  
  488.     return cmd.matches(rxmake_cmd);
  489. }
  490.  
  491. // True if CMD quits GDB
  492. bool is_quit_cmd (const string& cmd)
  493. {
  494.     return cmd.contains('q', 0); // `quit', `q', or whatever
  495. }
  496.  
  497. static bool starts_with(const string& cmd, const string& prefix)
  498. {
  499.     if (prefix == "")
  500.     return false;
  501.  
  502.     return cmd == prefix || 
  503.     (prefix.contains(' ', -1) && cmd.contains(prefix, 0)) ||
  504.     cmd.contains(prefix + " ", 0);
  505. }
  506.  
  507. // True if CMD is a printing command
  508. bool is_print_cmd(const string& cmd, GDBAgent *gdb)
  509. {
  510.     return (starts_with(cmd, gdb->print_command("", true)) ||
  511.         starts_with(cmd, gdb->print_command("", false)));
  512. }
  513.  
  514. // True if CMD is some other builtin command
  515. bool is_other_builtin_cmd(const string& cmd, GDBAgent *gdb)
  516. {
  517.     return is_print_cmd(cmd, gdb) ||
  518.     starts_with(cmd, gdb->enable_command("")) ||
  519.     starts_with(cmd, gdb->disable_command("")) ||
  520.     starts_with(cmd, gdb->delete_command("")) ||
  521.     starts_with(cmd, "make") ||
  522.     starts_with(cmd, "source");
  523. }
  524.  
  525.  
  526. // Fetch display expression from DISPLAY_CMD
  527. string get_display_expression (const string& display_cmd)
  528. {
  529. #if RUNTIME_REGEX
  530.     static regex rxdisplay_cmd("[ \t]*(disp|displ|displa|display|plot)[ \t]+");
  531. #endif
  532.  
  533.     string d(display_cmd);
  534.     return d.after(rxdisplay_cmd);
  535. }
  536.  
  537.  
  538. // Fetch breakpoint expression from CMD
  539. string get_break_expression (const string& cmd)
  540. {
  541.     string arg = cmd;
  542.  
  543.     if (arg.contains("stop", 0))
  544.     arg = arg.after(' ');        // Skip `in' or `at'
  545.  
  546.     // Fetch first word after command
  547.     arg = arg.after(' ');
  548.     arg += ' ';
  549.  
  550.     if (arg.contains('\'', 0))
  551.     arg = arg.through('\'', 1); // Handle GDB quoting
  552.     else
  553.     arg = arg.before(' ');
  554.  
  555.     return arg;
  556. }
  557.  
  558.  
  559. // True if ARG has the form `FILE:LINE'
  560. bool is_file_pos(const string& arg)
  561. {
  562. #if RUNTIME_REGEX
  563.     static regex rxfilepos("[^:]*:[1-9][0-9]*");
  564. #endif
  565.  
  566.     string a = arg;
  567.     strip_space(a);
  568.     return a.matches(rxfilepos);
  569. }
  570.  
  571. // Return true if CMD begins recording commands 
  572. bool starts_recording(const string& cmd)
  573. {
  574.     return cmd.contains("if", 0) ||
  575.     cmd.contains("while", 0) ||
  576.     cmd.contains("def", 0) ||
  577.     cmd.contains("doc", 0) ||
  578.     cmd.contains("comm", 0); 
  579. }
  580.  
  581. // Return true if CMD ends recording commands 
  582. bool ends_recording(const string& cmd)
  583. {
  584.     return cmd == "end";
  585. }
  586.  
  587.  
  588. //----------------------------------------------------------------------------
  589. // Handle `display' output
  590. //----------------------------------------------------------------------------
  591.  
  592. // Return index of first display in GDB_ANSWER; -1 if none
  593. int display_index (const string& gdb_answer, GDBAgent *gdb)
  594. {
  595. #if RUNTIME_REGEX
  596.     static regex rxgdb_begin_of_display("[1-9][0-9]*:  *[^ ]");
  597.     static regex rxdbx_begin_of_display("[^ \t\n)}][^=\n]* = ");
  598. #endif
  599.  
  600.     const regex *prx = 0;
  601.  
  602.     switch (gdb->type())
  603.     {
  604.     case GDB: 
  605.     case PYDB:
  606.     prx = &rxgdb_begin_of_display;
  607.     break;
  608.  
  609.     case DBX:
  610.     case XDB:
  611.     case JDB:
  612.     case PERL:
  613.     prx = &rxdbx_begin_of_display;
  614.     break;
  615.     }
  616.  
  617.     const regex& rx = *prx;
  618.  
  619.     for (unsigned i = 0; i < gdb_answer.length(); i++)
  620.     if (i == 0 || gdb_answer[i - 1] == '\n')
  621.         if (gdb_answer.contains(rx, i))
  622.         return i;
  623.  
  624.     return -1;
  625. }
  626.  
  627. // True if GDB_ANSWER contains some display
  628. bool contains_display (const string& gdb_answer, GDBAgent *gdb)
  629. {
  630.     return display_index(gdb_answer, gdb) >= 0;
  631. }
  632.  
  633. // Return index of possible display start; -1 if none
  634. int possible_begin_of_display (string gdb_answer, GDBAgent *gdb)
  635. {
  636.     int index = -1;
  637.  
  638.     if (index == -1)
  639.     index = display_index(gdb_answer, gdb);
  640.  
  641.     if (index == -1)
  642.     {
  643.     gdb_answer += "a";
  644.     index = display_index(gdb_answer, gdb);
  645.     }
  646.  
  647.     if (index == -1)
  648.     {
  649.     gdb_answer.at ("a", -1) = " a";
  650.     index = display_index(gdb_answer, gdb);
  651.     }
  652.  
  653.     if (index == -1)
  654.     {
  655.     gdb_answer.at (" a", -1) = ": a";
  656.     index = display_index(gdb_answer, gdb);
  657.     }
  658.  
  659.     return index;
  660. }
  661.  
  662.  
  663. // True if next non-space character in DISPLAYS is a newline
  664. static bool next_is_nl(const string& displays)
  665. {
  666.     unsigned int i = 0;
  667.     while (i < displays.length() && displays[i] == ' ')
  668.     i++;
  669.     return i < displays.length() && displays[i] == '\n';
  670. }
  671.  
  672. // Return next display from DISPLAYS ("" if none); remove it from
  673. // DISPLAYS
  674. string read_next_display (string& displays, GDBAgent *gdb)
  675. {
  676.     string next_display;
  677.  
  678.     // string old_displays = displays;
  679.     // clog << "read_next_display(" << quote(old_displays) << ")...\n";
  680.  
  681.     if (is_disabling(displays, gdb))
  682.     {
  683.     // After a `disabling' message, `display' output finishes
  684.     next_display = displays;
  685.     displays = "";
  686.     }
  687.     else
  688.     {
  689.     for (;;)
  690.     {
  691.         next_display += read_token(displays);
  692.  
  693.         if (displays == "")
  694.         break;        // All done
  695.  
  696.         if (next_display.contains(":()", -1))
  697.         {
  698.         // AIX DBX gives weird `members' like
  699.         // "pcg =     OM_PCGDownCasters:()\n(_root = 0x2004c248 ..."
  700.         // Be sure to continue such displays.
  701.         continue;
  702.         }
  703.  
  704.         if (next_is_nl(displays))
  705.         break;        // At end of display
  706.     }
  707.     }
  708.     displays = displays.after('\n');
  709.  
  710.     // clog << "read_next_display(" << quote(old_displays) << ") = "
  711.     //      << quote(next_display) << "\n";
  712.     return next_display;
  713. }
  714.  
  715. // Return "NR: NAME = " from DISPLAY
  716. string get_disp_value_str (const string& display, GDBAgent *gdb)
  717. {
  718.     string d(display);
  719.  
  720.     if (gdb->type() == XDB)
  721.     {
  722.     // For some types, XDB issues `NAME = VALUE', for others, `VALUE'.
  723.     // DDD compensates for this by prepending `NAME = '.
  724.     // In case we have `NAME = NAME = VALUE', strip first `NAME = '.
  725. #if RUNTIME_REGEX
  726.     static regex rxeqeq("[^{};,\n= ]+ = [^{}();,\n= ]+ = .*");
  727. #endif
  728.     if (d.matches(rxeqeq))
  729.         d = d.after(" = ");
  730.     }
  731.  
  732.     int nl_index = d.index('\n');
  733.     int eq_index = d.index(" = ");
  734.     if (eq_index >= 0 && (eq_index < nl_index || nl_index < 0))
  735.     return d.after(" = ");
  736.  
  737.     return d;
  738. }
  739.  
  740.  
  741.  
  742. //----------------------------------------------------------------------------
  743. // Handle `info display' output
  744. //----------------------------------------------------------------------------
  745.  
  746. #if RUNTIME_REGEX
  747. static regex rxgdb_begin_of_display_info("[1-9][0-9]*:   ");
  748. static regex rxdbx_begin_of_display_info("[(][1-9][0-9]*[)] ");
  749. #endif
  750.  
  751. // Return index of first display in GDB_ANSWER; -1 if none
  752. int display_info_index (const string& gdb_answer, GDBAgent *gdb)
  753. {
  754.     const regex *prx = 0;
  755.  
  756.     switch (gdb->type())
  757.     {
  758.     case GDB: 
  759.     case PYDB:
  760.     prx = &rxgdb_begin_of_display_info;
  761.     break;
  762.  
  763.     case DBX:
  764.     prx = &rxdbx_begin_of_display_info;
  765.     break;
  766.  
  767.     case JDB:
  768.     case XDB:
  769.     case PERL:
  770.     return -1;        // No displays in these debuggers
  771.     }
  772.  
  773.     const regex& rx = *prx;
  774.  
  775.     for (unsigned i = 0; i < gdb_answer.length(); i++)
  776.     if (i == 0 || gdb_answer[i - 1] == '\n')
  777.         if (gdb_answer.contains(rx, i))
  778.         return i;
  779.  
  780.     return -1;
  781. }
  782.  
  783. // Return first display info from GDB_ANSWER; "" if none.
  784. string read_first_disp_info (string& gdb_answer, GDBAgent *gdb)
  785. {
  786.     int i = display_info_index(gdb_answer, gdb);
  787.     if (i >= 0)
  788.     {
  789.     gdb_answer = gdb_answer.from(i);
  790.     return read_next_disp_info (gdb_answer, gdb);
  791.     }
  792.     gdb_answer = "";
  793.     return "";
  794. }
  795.  
  796.  
  797. // Return next display info from GDB_ANSWER; "" if none.
  798. string read_next_disp_info (string& gdb_answer, GDBAgent *gdb)
  799. {
  800.     switch (gdb->type())
  801.     {
  802.     case GDB:
  803.     case PYDB:
  804.     {
  805.     int startpos = gdb_answer.index (": ");
  806.     int i = startpos + 2;
  807.  
  808.     for (;;)
  809.     {
  810.         while (i < int(gdb_answer.length()) && gdb_answer[i] != '\n')
  811.         i++;
  812.         if (i >= int(gdb_answer.length()))
  813.         {
  814.         // Take entire remaining output as display
  815.         string next_disp_info = gdb_answer;
  816.         gdb_answer = "";
  817.         return next_disp_info;
  818.         }
  819.  
  820.         assert(gdb_answer[i] == '\n');
  821.         if (gdb_answer.contains(rxgdb_begin_of_display_info, i + 1))
  822.         {
  823.         // Use output up to `\n[0-9]' as display
  824.         string next_disp_info = gdb_answer.before(i);
  825.         gdb_answer = gdb_answer.after(i);
  826.         return next_disp_info;
  827.         }
  828.  
  829.         i++;
  830.     }
  831.     }
  832.  
  833.     case DBX:
  834.     {
  835.     string next_disp_info;
  836.     int i = gdb_answer.index('\n');
  837.     if (i > 0)
  838.     {
  839.         next_disp_info = gdb_answer.before(i);
  840.         gdb_answer = gdb_answer.after(i);
  841.     }
  842.     else
  843.     {
  844.         next_disp_info = gdb_answer;
  845.         gdb_answer = "";
  846.     }
  847.     return next_disp_info;
  848.     }
  849.  
  850.     case XDB:
  851.     case JDB:
  852.     case PERL:
  853.     break;            // FIXME
  854.     }
  855.  
  856.     return "";
  857. }
  858.  
  859. // Remove and return "NR: " from DISPLAY.
  860. string get_info_disp_str (string& display_info, GDBAgent *gdb)
  861. {
  862.     switch (gdb->type())
  863.     {
  864.     case GDB:
  865.     case PYDB:
  866.     return display_info.after (":   ");
  867.  
  868.     case DBX:
  869.     return display_info.after (") ");
  870.  
  871.     case XDB:
  872.     case JDB:
  873.     case PERL:
  874.     return "";        // FIXME
  875.     }
  876.  
  877.     return "";
  878. }
  879.  
  880. // Check whether `disabled' entry in INFO_DISP_STR indicates an enabled display
  881. bool disp_is_disabled (const string& info_disp_str, GDBAgent *gdb)
  882. {
  883.     switch (gdb->type())
  884.     {
  885.     case GDB:
  886.     case PYDB:
  887.     return info_disp_str.length() > 0 && info_disp_str[0] == 'n';
  888.  
  889.     case DBX:
  890.     return false;        // no display disabling in dbx
  891.  
  892.     case XDB:
  893.     case JDB:
  894.     case PERL:
  895.     return false;        // FIXME
  896.     }
  897.  
  898.     return false;
  899. }
  900.  
  901.  
  902.  
  903. //----------------------------------------------------------------------------
  904. // Process `display' output
  905. //----------------------------------------------------------------------------
  906.  
  907. // Remove and return display number from DISPLAY
  908. string  read_disp_nr_str (string& display, GDBAgent *gdb)
  909. {
  910.     switch (gdb->type())
  911.     {
  912.     case GDB:
  913.     case PYDB:
  914.     {
  915. #if RUNTIME_REGEX
  916.     static regex rxgdb_disp_nr("[1-9][0-9]*");
  917. #endif
  918.  
  919.     string disp_nr = display.through (rxgdb_disp_nr);
  920.     display = display.after (": ");
  921.     return disp_nr;
  922.     }
  923.     case DBX:
  924.     return read_disp_name(display, gdb);
  925.  
  926.     case XDB:
  927.     case JDB:
  928.     case PERL:
  929.     return "";        // FIXME
  930.     }
  931.  
  932.     return "";
  933. }
  934.  
  935. // Remove and return display name from DISPLAY
  936. string read_disp_name (string& display, GDBAgent *gdb)
  937. {
  938.     strip_leading_space(display);
  939.     string name = display.before (" = ");
  940.     display = get_disp_value_str(display, gdb);
  941.     return name;
  942. }
  943.  
  944. // True if some display has been disabled
  945. bool is_disabling(const string& value, GDBAgent *gdb)
  946. {
  947.     return gdb->type() == GDB && value.contains("\nDisabling display ");
  948. }
  949.  
  950. // True if VALUE is an valid value (i.e., no error message)
  951. bool is_valid(const string& value, GDBAgent *gdb)
  952. {
  953.     if (gdb->program_language() == LANGUAGE_PERL)
  954.     return true;        // Everything is valid in perl
  955.  
  956.     // If VALUE ends in two words, it is an error message like `not
  957.     // active' or `no symbol in current context.'.  XDB issues
  958.     // `Unknown name "Foo" (UE369)' and `Local is not active (UE421)'.
  959. #if RUNTIME_REGEX
  960.     static regex rxinvalid_value("("
  961.                  "[a-zA-Z]+ [a-zA-Z]+.*"
  962.                  "|.*[a-zA-Z]+ [a-zA-Z]+(\\.|>)?"
  963.                  ")\n?");
  964. #endif
  965.  
  966.     return !value.contains("Unknown name") 
  967.     && !value.contains("not active")
  968.     && !value.contains("not defined")
  969.     && !value.matches(rxinvalid_value);
  970. }
  971.  
  972.  
  973. //-----------------------------------------------------------------------------
  974. // Handle `where' output
  975. //-----------------------------------------------------------------------------
  976.  
  977. // Fetch current scope from GDB `where' output (a function name).
  978. // This also works for JDB `where' output.
  979. string get_scope(const string& where_output)
  980. {
  981.     // The word before the first parenthesis is the current function.
  982.     int index = where_output.index('(');
  983.     if (index < 0)
  984.     return "";        // no current scope
  985.  
  986.     do {
  987.     index--;
  988.     } while (index >= 0 && isspace(where_output[index]));
  989.  
  990.     int end_of_name = index + 1;
  991.  
  992.     do {
  993.     index--;
  994.     } while (index >= 0 && !isspace(where_output[index]));
  995.  
  996.     int start_of_name = index + 1;
  997.  
  998.     return ((string &)where_output).at(start_of_name, 
  999.                        end_of_name - start_of_name);
  1000. }
  1001.