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 / pydb / pydbsupt.py < prev    next >
Encoding:
Python Source  |  1998-08-26  |  7.9 KB  |  251 lines

  1. # $Id: pydbsupt.py,v 1.2 1998/08/26 09:26:33 zeller Exp $
  2. """Support functions for pydb, the Python debugger that works with ddd"""
  3.  
  4. import string
  5.  
  6. """Breakpoint class for interface with ddd.
  7.  
  8.    Implements temporary breakpoints, ignore counts, disabling and
  9.    (re)-enabling, and conditionals.
  10.  
  11.    Breakpoints are indexed by number through bpbynumber and by the
  12.    file,line tuple using bplist.  The former points to a single
  13.    instance of class Breakpoint.  The latter points to a list of
  14.    such instances since there may be more than one breakpoint per line.
  15.    """
  16.  
  17. class Breakpoint:
  18.     next = 1      # Next bp to be assigned
  19.     bplist = {}   # indexed by (file, lineno) tuple
  20.     bpbynumber = [None]    # Each entry is None or an instance of Bpt
  21.                            # index 0 is unused, except for marking an
  22.                            # effective break .... see effective()
  23.  
  24.     def __init__(self, file, line, temporary=0):
  25.         self.file = file
  26.         self.line = line
  27.         self.cond = None
  28.         self.temporary = temporary
  29.         self.enabled = 1
  30.         self.ignore = 0
  31.         self.hits = 0
  32.         self.number = Breakpoint.next
  33.         Breakpoint.next = Breakpoint.next + 1
  34.         # Build the two lists
  35.         self.bpbynumber.append(self)
  36.         if self.bplist.has_key((file, line)):
  37.             self.bplist[file, line].append(self)
  38.         else:
  39.             self.bplist[file, line] = [self]
  40.  
  41.         
  42.     def deleteMe(self):
  43.         index = (self.file, self.line)
  44.         self.bpbynumber[self.number] = None   # No longer in list
  45.         self.bplist[index].remove(self)
  46.         if not self.bplist[index]:
  47.             # No more bp for this f:l combo
  48.             del self.bplist[index]
  49.  
  50.     def enable(self):
  51.         self.enabled = 1
  52.  
  53.     def disable(self):
  54.         self.enabled = 0
  55.  
  56.     def bpprint(self):
  57.         if self.temporary:
  58.            disp = 'del  '
  59.         else:
  60.            disp = 'keep '
  61.         if self.enabled:
  62.            disp = disp + 'yes'
  63.         else:
  64.            disp = disp + 'no '
  65.         print '%-4dbreakpoint     %s at %s:%d' % (self.number, disp, self.file, self.line)
  66.         if self.cond:
  67.             print '\tstop only if %s' % (self.cond,)
  68.         if self.ignore:
  69.             print '\tignore next %d hits' % (self.ignore)
  70.         if (self.hits):
  71.             if (self.hits > 1): ss = 's'
  72.             else: ss = ''
  73.             print '\tbreakpoint already hit %d time%s' % (self.hits,ss)
  74.  
  75. # Determines if there is an effective (active) breakpoint at this
  76. # line of code.  Returns breakpoint number or 0 if none
  77. def effective(file, line, frame):
  78.     """Determine which breakpoint for this file:line is to be
  79.        acted upon.  Called only if we know there is a bpt at this
  80.        location.  Returns breakpoint that was triggered and a flag
  81.        that indicates if it is ok to delete a temporary bp."""
  82.     possibles = Breakpoint.bplist[file,line]
  83.     for i in range(0, len(possibles)):
  84.         b = possibles[i]
  85.         if b.enabled == 0:
  86.             continue
  87.         # Count every hit when bp is enabled
  88.         b.hits = b.hits + 1
  89.         if not b.cond:
  90.             # If unconditional, and ignoring, go on to next, else break
  91.             if b.ignore > 0:
  92.                 b.ignore = b.ignore -1
  93.                 continue
  94.             else:
  95.                 # breakpoint and marker that's ok to delete if temporary
  96.                 return (b,1)
  97.         else:
  98.             # Conditional bp.
  99.             # Ignore count applies only to those bpt hits where the
  100.             # condition evaluates to true.
  101.             try:
  102.                 val = eval(b.cond, frame.f_globals, frame.f_locals) 
  103.                 if val:
  104.                     if b.ignore > 0:
  105.                         b.ignore = b.ignore -1
  106.                         # continue
  107.                     else:
  108.                         return (b,1)
  109.                 # else:
  110.                 #    continue
  111.             except:
  112.                 # if eval fails, most conservative thing is to stop
  113.                 # on breakpoint regardless of ignore count.
  114.                 # Don't delete temporary, as another hint to user.
  115.                 return (b,0)
  116.     return (None, None)
  117.  
  118. class Display:
  119.     displayNext = 1
  120.     displayList = []
  121.  
  122.     def __init__(self):
  123.         pass
  124.  
  125.     def displayIndex(self, frame):
  126.         if not frame:
  127.             return None
  128.         # return suitable index for displayList
  129.         code = frame.f_code
  130.         return (code.co_name, code.co_filename, code.co_firstlineno)
  131.  
  132.     def displayAny(self, frame):
  133.         # display any items that are active
  134.         if not frame:
  135.             return
  136.         index = self.displayIndex(frame)
  137.         for dp in Display.displayList:
  138.             if dp.code == index and dp.enabled:
  139.                 print dp.displayMe(frame)
  140.  
  141.     def displayAll(self):
  142.         # List all display items; return 0 if none
  143.         any = 0
  144.         for dp in Display.displayList:
  145.             if not any:
  146.                 print """Auto-display expressions now in effect:
  147. Num Enb Expression"""
  148.                 any = 1
  149.             dp.params()
  150.         return any
  151.  
  152.     def deleteOne(self, i):
  153.         for dp in Display.displayList:
  154.             if i == dp.number:
  155.                 dp.deleteMe()
  156.                 return
  157.  
  158.     def enable(self, i, flag):
  159.         for dp in Display.displayList:
  160.             if i == dp.number:
  161.                 if flag:
  162.                    dp.enable()
  163.                 else:
  164.                    dp.disable()
  165.                 return
  166.  
  167. class DisplayNode(Display):
  168.  
  169.     def __init__(self, frame, arg, format):
  170.         self.code = self.displayIndex(frame)
  171.         self.format = format
  172.         self.arg = arg
  173.         self.enabled = 1
  174.         self.number = Display.displayNext
  175.         Display.displayNext = Display.displayNext + 1
  176.         Display.displayList.append(self)
  177.  
  178.     def displayMe(self, frame):
  179.         if not frame:
  180.             return 'No symbol "' + self.arg + '" in current context.'
  181.         try:
  182.             val = eval(self.arg, frame.f_globals, frame.f_locals)
  183.         except:
  184.             return 'No symbol "' + self.arg + '" in current context.'
  185.         #format and print
  186.         what = self.arg
  187.         if self.format:
  188.             what = self.format + ' ' + self.arg
  189.             val = self.printf(val, self.format)
  190.         return '%d: %s = %s' % (self.number, what, val)
  191.  
  192.     pconvert = {'c':chr, 'x': hex, 'o': oct, 'f': float, 's': str}
  193.     twos = ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
  194.             '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111')
  195.  
  196.     def printf(self, val, fmt):
  197.         if not fmt:
  198.             fmt = ' ' # not 't' nor in pconvert
  199.         # Strip leading '/'
  200.         if fmt[0] == '/':
  201.             fmt = fmt[1:]
  202.         f = fmt[0]
  203.         if f in self.pconvert.keys():
  204.             try:
  205.                 return apply(self.pconvert[f], (val,))
  206.             except:
  207.                 return str(val)
  208.         # binary (t is from 'twos')
  209.         if f == 't':
  210.             try:
  211.                 res = ''
  212.                 while val:
  213.                     res = self.twos[val & 0xf] + res
  214.                     val = val >> 4
  215.                 return res
  216.             except:
  217.                 return str(val)
  218.         return str(val)
  219.         
  220.     def checkValid(self, frame):
  221.         # Check if valid for this frame, and if not, delete display
  222.         # To be used by code that creates a displayNode and only then.
  223.         res = self.displayMe(frame)
  224.         if string.split(res)[0] == 'No':
  225.             self.deleteMe()
  226.             # reset counter
  227.             Display.displayNext = Display.displayNext - 1
  228.         return res
  229.  
  230.     def params(self):
  231.         #print format and item to display
  232.         pad = ' ' * (3 - len(`self.number`))
  233.         if self.enabled:
  234.            what = ' y  '
  235.         else:
  236.            what = ' n  '
  237.         if self.format:
  238.            what = what + self.format + ' '
  239.         what = pad + what + self.arg
  240.         print '%d:%s' % (self.number, what)
  241.  
  242.     def deleteMe(self):
  243.         Display.displayList.remove(self)
  244.  
  245.     def disable(self):
  246.         self.enabled = 0
  247.  
  248.     def enable(self):
  249.         self.enabled = 1
  250.  
  251.