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 / logplayer.C < prev    next >
C/C++ Source or Header  |  1998-11-24  |  9KB  |  400 lines

  1. // $Id: logplayer.C,v 1.13 1998/11/24 15:07:47 zeller Exp $ -*- C++ -*-
  2. // Debugger replacement, playing .log files
  3.  
  4. // Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@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 logplayer_rcsid[] = 
  30.     "$Id: logplayer.C,v 1.13 1998/11/24 15:07:47 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "logplayer.h"
  37.  
  38. #include "assert.h"
  39. #include "bool.h"
  40. #include "strclass.h"
  41. #include "cook.h"
  42. #include "config.h"
  43.  
  44. #include <iostream.h>
  45. #include <fstream.h>
  46. #include <iomanip.h>
  47. #include <stdlib.h>
  48. #include <stdio.h>
  49. #include <unistd.h>
  50. #include <ctype.h>
  51.  
  52. #include <setjmp.h>
  53. #include <signal.h>
  54. #include <string.h>        // strerror()
  55.  
  56. // Nico van Waes <nico@yegal.njit.edu> says: under Solaris 2.6, one
  57. // must include <sys/types.h> and <sys/int_types.h> before
  58. // <termios.h>.
  59. #if HAVE_SYS_TYPES_H
  60. #include <sys/types.h>
  61. #endif
  62.  
  63. #if HAVE_SYS_INT_TYPES_H
  64. #include <sys/int_types.h>
  65. #endif
  66.  
  67. #if HAVE_TERMIOS_H
  68. #include <termios.h>
  69. #endif
  70.  
  71. extern "C" {
  72. #if HAVE_TCDRAIN && !HAVE_TCDRAIN_DECL && !defined(tcdrain)
  73.     int tcdrain(int filedes);
  74. #endif
  75. }
  76.  
  77. #ifndef EXIT_SUCCESS
  78. #define EXIT_SUCCESS 0
  79. #endif
  80.  
  81. #ifndef EXIT_FAILURE
  82. #define EXIT_FAILURE 1
  83. #endif
  84.  
  85. #ifndef STDOUT_FILENO
  86. #define STDOUT_FAILNO 1
  87. #endif
  88.  
  89. typedef void (*SignalProc)(SIGHANDLERARGS);
  90.  
  91. static jmp_buf main_loop_env;
  92.  
  93. // Handle interrupts
  94. static int intr(int sig)
  95. {
  96.     signal(SIGINT, (SignalProc)intr);
  97.     longjmp(main_loop_env, sig);
  98.  
  99.     return 0;            // Never reached
  100. }
  101.  
  102. static const char *usage = 
  103. "`/S' search S in commands  `:N' goto Nth command   `.' show expected command"
  104. "\n"
  105. "`/'  search again          `:'  list all commands  `!' issue expected command"
  106. "\n";
  107.  
  108. static string last_out;
  109.  
  110. static void put(const string& s)
  111. {
  112.     write(STDOUT_FILENO, s.chars(), s.length());
  113.     last_out += s;
  114.  
  115. #if HAVE_TCDRAIN || defined(tcdrain)
  116.     if (isatty(STDOUT_FILENO))
  117.     {
  118.     tcdrain(STDOUT_FILENO);
  119.     }
  120. #endif
  121. }
  122.  
  123. // Simulate a debugger via the DDD log LOGNAME.  If a command matches
  124. // a DDD command in LOGNAME, issue the appropriate answer.
  125. void logplayer(const string& logname)
  126. {
  127.     // All this is really ugly.  Works well as a hack for debugging DDD,
  128.     // but not really worth anything else.
  129.  
  130.     static ifstream log(logname);
  131.     if (log.bad())
  132.     {
  133.     (void) fopen(logname, "r");
  134.     perror(logname);
  135.     exit(EXIT_FAILURE);
  136.     }
  137.  
  138.     put("[Playing " + quote(logname) + ".  Use `?' for help]\n");
  139.  
  140.     static string out;
  141.     static string ddd_line;
  142.     static string last_prompt;
  143.     static bool initializing = true;
  144.     static bool scanning = false;
  145.     static bool out_seen = false;
  146.     static bool wrapped = false;
  147.     static bool echoing = false;
  148.     static streampos scan_start, last_input;
  149.     static string expecting;
  150.     static int command_no = 0;
  151.     static int command_no_start = 0;
  152.     static bool ignore_next_input = false;
  153.  
  154.     signal(SIGINT, (SignalProc)intr);
  155.     if (setjmp(main_loop_env) != 0)
  156.     {
  157.     put("Quit\n");
  158.  
  159.     scanning = false;
  160.     wrapped  = false;
  161.     log.clear();
  162.     log.seekg(last_input);
  163.     command_no = command_no_start;
  164.     out = "";
  165.     ddd_line = "";
  166.     ignore_next_input = true;
  167.     }
  168.  
  169.     for (;;)
  170.     {
  171.     streampos current = log.tellg();
  172.     if (!scanning)
  173.     {
  174.         scan_start = current;
  175.         command_no_start = command_no;
  176.     }
  177.  
  178.     // Read line from log
  179.     char buffer[1024];
  180.     log.getline(buffer, sizeof buffer);
  181.     string log_line(buffer);
  182.  
  183.     if (out_seen && log_line.contains("   ", 0))
  184.     {
  185.         // Continuation line
  186.         out += unquote(log_line.from('"'));
  187.     }
  188.     else if (out != "")
  189.     {
  190.         // Send out accumulated output
  191.         if (!scanning)
  192.         {
  193.         if (out.contains(ddd_line, 0))
  194.             echoing = true;
  195.         put(out);
  196.         }
  197.         out = "";
  198.     }
  199.  
  200.     if (log_line.contains("<- ", 0))
  201.     {
  202.         assert(out == "");
  203.  
  204.         // Output line
  205.         out = unquote(log_line.from('"'));
  206.         out_seen = true;
  207.     }
  208.  
  209.     if (out_seen && log_line.contains("-> ", 0))
  210.     {
  211.         // Handle input
  212.         string in = unquote(log_line.from('"'));
  213.         if (in.contains('\n', -1))
  214.         in = in.before('\n', -1);
  215.         command_no++;
  216.  
  217.         if (ddd_line.contains('/', 0) || ddd_line.contains(':', 0))
  218.         {
  219.         static string pattern;
  220.         char c = ddd_line[0];
  221.         string p = ddd_line.after(0);
  222.         if (p != "" || c == ':')
  223.             pattern = p;
  224.         if (pattern == "" ||
  225.             (c == ':' && command_no == atoi(pattern)) ||
  226.             (c == '/' && (pattern == "" || in.contains(pattern))))
  227.         {
  228.             // Report line
  229.             ostrstream os;
  230.             os << setw(4) << command_no << " " << in << "\n";
  231.             put(os);
  232.  
  233.             if (c == '/' || pattern != "")
  234.             {
  235.             // Stop here
  236.             scanning = false;
  237.             scan_start = current;
  238.             command_no_start = command_no - 1;
  239.             }
  240.         }
  241.         }
  242.  
  243.         if (!scanning)
  244.         {
  245.         last_input = scan_start;
  246.         initializing = false;
  247.  
  248.         // Read command from DDD
  249.         if (last_out.contains('\n'))
  250.         {
  251.             string prompt = last_out.after('\n', -1);
  252.             if (prompt != "")
  253.             {
  254.             if (prompt.contains('('))
  255.                 prompt = prompt.from('(', -1);
  256.  
  257.             last_prompt = prompt;
  258.             }
  259.         }
  260.  
  261.         if (!last_out.contains(last_prompt, -1))
  262.             put(last_prompt);
  263.  
  264.         last_out = "";
  265.  
  266.         char *s = fgets(buffer, sizeof buffer, stdin);
  267.         if (ignore_next_input)
  268.         {
  269.             s = fgets(buffer, sizeof buffer, stdin);
  270.             ignore_next_input = false;
  271.         }
  272.         if (s == NULL)
  273.             exit(EXIT_SUCCESS);
  274.  
  275.         ddd_line = buffer;
  276.         if (ddd_line.contains('\n', -1))
  277.             ddd_line = ddd_line.before('\n', -1);
  278.  
  279.         if (echoing && ddd_line != "" && !isalpha(ddd_line[0]))
  280.             put(ddd_line + "\r\n");
  281.  
  282.         if (ddd_line.contains('q', 0))
  283.             exit(EXIT_SUCCESS);
  284.  
  285.         if ((ddd_line.contains("list ", 0) || 
  286.              ddd_line.contains("l ", 0)) && 
  287.             (ddd_line.contains(" 1,") || 
  288.              ddd_line.contains(":1,") || 
  289.              ddd_line.contains(" 1-")))
  290.         {
  291.             // Send the log file instead of a source
  292.             if (echoing)
  293.             put(ddd_line + "\r\n");
  294.  
  295.             ifstream is(logname);
  296.             int line = 1;
  297.             bool at_start_of_line = true;
  298.  
  299.             ostrstream os;
  300.             for (;;)
  301.             {
  302.             char c;
  303.             is.get(c);
  304.             if (is.eof())
  305.                 break;
  306.  
  307.             if (at_start_of_line)
  308.             {
  309.                 os << line << '\t';
  310.                 at_start_of_line = false;
  311.             }
  312.  
  313.             os << c;
  314.  
  315.             if (c == '\n')
  316.             {
  317.                 line++;
  318.                 at_start_of_line = true;
  319.             }
  320.             }
  321.  
  322.             put(string(os));
  323.             scanning = false;
  324.         }
  325.         }
  326.  
  327.         if (!scanning && ddd_line == ".")
  328.         {
  329.         ostrstream os;
  330.         os << "Expecting " 
  331.            << command_no << " " << quote(in) << "\n";
  332.         put(os);
  333.         log.seekg(scan_start);
  334.         command_no = command_no_start;
  335.         }
  336.         else if (!scanning && ddd_line == "?")
  337.         {
  338.         put(usage);
  339.         log.seekg(scan_start);
  340.         command_no = command_no_start;
  341.         }
  342.         else if (ddd_line == in || ddd_line == "!" || ddd_line == "")
  343.         {
  344.         // Okay, got it
  345.         scanning = false;
  346.         }
  347.         else if (!scanning)
  348.         {
  349.         // Bad match: try to find this command in the log
  350.         expecting = in;
  351.         scanning = true;
  352.         wrapped = false;
  353.         }
  354.     }
  355.  
  356.     if (log.eof())
  357.     {
  358.         if (scanning && wrapped)
  359.         {
  360.         // Nothing found.  Don't reply.
  361.         if (echoing && (ddd_line == "" || isalpha(ddd_line[0])))
  362.             put(ddd_line + "\r\n");
  363.  
  364.         scanning = false;
  365.         log.clear();
  366.         log.seekg(scan_start);
  367.         command_no = command_no_start;
  368.         }
  369.         else if (initializing)
  370.         {
  371.         // No prompt found
  372.         cerr << logname << ": invalid or incomplete log\n";
  373.         exit(EXIT_FAILURE);
  374.         }
  375.         else
  376.         {
  377.         // Try from the start
  378.         wrapped = true;
  379.         out_seen = false;
  380.         log.clear();
  381.         log.seekg(0);
  382.         command_no = 0;
  383.         }
  384.     }
  385.     }
  386. }
  387.  
  388. #if MAIN
  389. int main(int argc, char *argv[])
  390. {
  391.     static string logname;
  392.     if (argc > 1)
  393.     logname = argv[1];
  394.     else
  395.     logname = string(getenv("HOME")) + "/.ddd/log";
  396.  
  397.     logplayer(logname);
  398. }
  399. #endif
  400.