byebug 11.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +897 -0
  3. data/CONTRIBUTING.md +58 -0
  4. data/GUIDE.md +1806 -0
  5. data/LICENSE +23 -0
  6. data/README.md +199 -0
  7. data/exe/byebug +6 -0
  8. data/ext/byebug/breakpoint.c +517 -0
  9. data/ext/byebug/byebug.c +905 -0
  10. data/ext/byebug/byebug.h +143 -0
  11. data/ext/byebug/context.c +673 -0
  12. data/ext/byebug/extconf.rb +12 -0
  13. data/ext/byebug/locker.c +96 -0
  14. data/ext/byebug/threads.c +230 -0
  15. data/lib/byebug.rb +3 -0
  16. data/lib/byebug/attacher.rb +48 -0
  17. data/lib/byebug/breakpoint.rb +111 -0
  18. data/lib/byebug/command.rb +111 -0
  19. data/lib/byebug/command_list.rb +34 -0
  20. data/lib/byebug/commands.rb +40 -0
  21. data/lib/byebug/commands/break.rb +112 -0
  22. data/lib/byebug/commands/catch.rb +78 -0
  23. data/lib/byebug/commands/condition.rb +55 -0
  24. data/lib/byebug/commands/continue.rb +68 -0
  25. data/lib/byebug/commands/debug.rb +38 -0
  26. data/lib/byebug/commands/delete.rb +55 -0
  27. data/lib/byebug/commands/disable.rb +33 -0
  28. data/lib/byebug/commands/disable/breakpoints.rb +42 -0
  29. data/lib/byebug/commands/disable/display.rb +43 -0
  30. data/lib/byebug/commands/display.rb +66 -0
  31. data/lib/byebug/commands/down.rb +45 -0
  32. data/lib/byebug/commands/edit.rb +69 -0
  33. data/lib/byebug/commands/enable.rb +33 -0
  34. data/lib/byebug/commands/enable/breakpoints.rb +42 -0
  35. data/lib/byebug/commands/enable/display.rb +43 -0
  36. data/lib/byebug/commands/finish.rb +57 -0
  37. data/lib/byebug/commands/frame.rb +57 -0
  38. data/lib/byebug/commands/help.rb +64 -0
  39. data/lib/byebug/commands/history.rb +39 -0
  40. data/lib/byebug/commands/info.rb +37 -0
  41. data/lib/byebug/commands/info/breakpoints.rb +65 -0
  42. data/lib/byebug/commands/info/display.rb +49 -0
  43. data/lib/byebug/commands/info/file.rb +80 -0
  44. data/lib/byebug/commands/info/line.rb +35 -0
  45. data/lib/byebug/commands/info/program.rb +49 -0
  46. data/lib/byebug/commands/interrupt.rb +34 -0
  47. data/lib/byebug/commands/irb.rb +50 -0
  48. data/lib/byebug/commands/kill.rb +45 -0
  49. data/lib/byebug/commands/list.rb +159 -0
  50. data/lib/byebug/commands/method.rb +53 -0
  51. data/lib/byebug/commands/next.rb +40 -0
  52. data/lib/byebug/commands/pry.rb +41 -0
  53. data/lib/byebug/commands/quit.rb +42 -0
  54. data/lib/byebug/commands/restart.rb +64 -0
  55. data/lib/byebug/commands/save.rb +72 -0
  56. data/lib/byebug/commands/set.rb +79 -0
  57. data/lib/byebug/commands/show.rb +45 -0
  58. data/lib/byebug/commands/skip.rb +85 -0
  59. data/lib/byebug/commands/source.rb +40 -0
  60. data/lib/byebug/commands/step.rb +40 -0
  61. data/lib/byebug/commands/thread.rb +34 -0
  62. data/lib/byebug/commands/thread/current.rb +37 -0
  63. data/lib/byebug/commands/thread/list.rb +43 -0
  64. data/lib/byebug/commands/thread/resume.rb +45 -0
  65. data/lib/byebug/commands/thread/stop.rb +43 -0
  66. data/lib/byebug/commands/thread/switch.rb +46 -0
  67. data/lib/byebug/commands/tracevar.rb +54 -0
  68. data/lib/byebug/commands/undisplay.rb +51 -0
  69. data/lib/byebug/commands/untracevar.rb +36 -0
  70. data/lib/byebug/commands/up.rb +45 -0
  71. data/lib/byebug/commands/var.rb +37 -0
  72. data/lib/byebug/commands/var/all.rb +41 -0
  73. data/lib/byebug/commands/var/args.rb +39 -0
  74. data/lib/byebug/commands/var/const.rb +49 -0
  75. data/lib/byebug/commands/var/global.rb +37 -0
  76. data/lib/byebug/commands/var/instance.rb +39 -0
  77. data/lib/byebug/commands/var/local.rb +39 -0
  78. data/lib/byebug/commands/where.rb +53 -0
  79. data/lib/byebug/context.rb +157 -0
  80. data/lib/byebug/core.rb +115 -0
  81. data/lib/byebug/errors.rb +29 -0
  82. data/lib/byebug/frame.rb +185 -0
  83. data/lib/byebug/helpers/bin.rb +47 -0
  84. data/lib/byebug/helpers/eval.rb +126 -0
  85. data/lib/byebug/helpers/file.rb +63 -0
  86. data/lib/byebug/helpers/frame.rb +75 -0
  87. data/lib/byebug/helpers/parse.rb +75 -0
  88. data/lib/byebug/helpers/path.rb +40 -0
  89. data/lib/byebug/helpers/reflection.rb +19 -0
  90. data/lib/byebug/helpers/string.rb +33 -0
  91. data/lib/byebug/helpers/thread.rb +67 -0
  92. data/lib/byebug/helpers/toggle.rb +62 -0
  93. data/lib/byebug/helpers/var.rb +54 -0
  94. data/lib/byebug/history.rb +130 -0
  95. data/lib/byebug/interface.rb +146 -0
  96. data/lib/byebug/interfaces/local_interface.rb +44 -0
  97. data/lib/byebug/interfaces/remote_interface.rb +50 -0
  98. data/lib/byebug/interfaces/script_interface.rb +33 -0
  99. data/lib/byebug/interfaces/test_interface.rb +67 -0
  100. data/lib/byebug/option_setter.rb +95 -0
  101. data/lib/byebug/printers/base.rb +68 -0
  102. data/lib/byebug/printers/plain.rb +44 -0
  103. data/lib/byebug/printers/texts/base.yml +115 -0
  104. data/lib/byebug/printers/texts/plain.yml +33 -0
  105. data/lib/byebug/processors/command_processor.rb +173 -0
  106. data/lib/byebug/processors/control_processor.rb +24 -0
  107. data/lib/byebug/processors/post_mortem_processor.rb +18 -0
  108. data/lib/byebug/processors/script_processor.rb +49 -0
  109. data/lib/byebug/remote.rb +85 -0
  110. data/lib/byebug/remote/client.rb +57 -0
  111. data/lib/byebug/remote/server.rb +47 -0
  112. data/lib/byebug/runner.rb +198 -0
  113. data/lib/byebug/setting.rb +79 -0
  114. data/lib/byebug/settings/autoirb.rb +29 -0
  115. data/lib/byebug/settings/autolist.rb +29 -0
  116. data/lib/byebug/settings/autopry.rb +29 -0
  117. data/lib/byebug/settings/autosave.rb +17 -0
  118. data/lib/byebug/settings/basename.rb +16 -0
  119. data/lib/byebug/settings/callstyle.rb +20 -0
  120. data/lib/byebug/settings/fullpath.rb +16 -0
  121. data/lib/byebug/settings/histfile.rb +20 -0
  122. data/lib/byebug/settings/histsize.rb +20 -0
  123. data/lib/byebug/settings/linetrace.rb +22 -0
  124. data/lib/byebug/settings/listsize.rb +21 -0
  125. data/lib/byebug/settings/post_mortem.rb +27 -0
  126. data/lib/byebug/settings/savefile.rb +20 -0
  127. data/lib/byebug/settings/stack_on_error.rb +15 -0
  128. data/lib/byebug/settings/width.rb +20 -0
  129. data/lib/byebug/source_file_formatter.rb +71 -0
  130. data/lib/byebug/subcommands.rb +54 -0
  131. data/lib/byebug/version.rb +8 -0
  132. metadata +199 -0
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2018 David Rodríguez <deivid.rodriguez@riseup.net>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,199 @@
1
+ # Byebug
2
+
3
+ [![Version][gem]][gem_url]
4
+ [![Tidelift][tid]][tid_url]
5
+ [![Coverage][cov]][cov_url]
6
+ [![Gitter][irc]][irc_url]
7
+
8
+ [gem]: https://img.shields.io/gem/v/byebug.svg
9
+ [tid]: https://tidelift.com/badges/github/deivid-rodriguez/byebug
10
+ [cov]: https://api.codeclimate.com/v1/badges/f1a1bec582752c22da80/test_coverage
11
+ [irc]: https://img.shields.io/badge/IRC%20(gitter)-devs%20%26%20users-brightgreen.svg
12
+
13
+ [gem_url]: https://rubygems.org/gems/byebug
14
+ [tid_url]: https://tidelift.com/subscription/pkg/rubygems-byebug?utm_source=rubygems-byebug&utm_medium=readme_badge
15
+ [cov_url]: https://codeclimate.com/github/deivid-rodriguez/byebug/test_coverage
16
+ [irc_url]: https://gitter.im/deivid-rodriguez/byebug
17
+
18
+ Byebug is a simple to use and feature rich debugger for Ruby. It uses the
19
+ TracePoint API for execution control and the Debug Inspector API for call stack
20
+ navigation. Therefore, Byebug doesn't depend on internal core sources. Byebug is also
21
+ fast because it is developed as a C extension and reliable because it is supported
22
+ by a full test suite.
23
+
24
+ The debugger permits the ability to understand what is going on _inside_ a Ruby program
25
+ while it executes and offers many of the traditional debugging features such as:
26
+
27
+ * Stepping: Running your program one line at a time.
28
+ * Breaking: Pausing the program at some event or specified instruction, to
29
+ examine the current state.
30
+ * Evaluating: Basic REPL functionality, although [pry] does a better job at
31
+ that.
32
+ * Tracking: Keeping track of the different values of your variables or the
33
+ different lines executed by your program.
34
+
35
+ ## Build Status
36
+
37
+ Linux [![Cir][cir]][cir_url]
38
+ Windows [![Vey][vey]][vey_url]
39
+
40
+ [cir]: https://circleci.com/gh/deivid-rodriguez/byebug/tree/master.svg?style=svg
41
+ [tra]: https://api.travis-ci.org/deivid-rodriguez/byebug.svg?branch=master
42
+ [vey]: https://ci.appveyor.com/api/projects/status/github/deivid-rodriguez/byebug?svg=true
43
+
44
+ [cir_url]: https://circleci.com/gh/deivid-rodriguez/byebug/tree/master
45
+ [tra_url]: https://travis-ci.org/deivid-rodriguez/byebug
46
+ [vey_url]: https://ci.appveyor.com/project/deivid-rodriguez/byebug
47
+
48
+ ## Requirements
49
+
50
+ MRI 2.3.0 or higher.
51
+
52
+ ## Install
53
+
54
+ ```shell
55
+ gem install byebug
56
+ ```
57
+
58
+ Alternatively, if you use `bundler`:
59
+
60
+ ```shell
61
+ bundle add byebug --group "development, test"
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ### From within the Ruby code
67
+
68
+ Simply include `byebug` wherever you want to start debugging and the execution will
69
+ stop there. For example, if you were debugging Rails, you would add `byebug` to
70
+ your code:
71
+
72
+ ```ruby
73
+ def index
74
+ byebug
75
+ @articles = Article.find_recent
76
+ end
77
+ ```
78
+
79
+ And then start a Rails server:
80
+
81
+ ```shell
82
+ bin/rails s
83
+ ```
84
+
85
+ Once the execution gets to your `byebug` command, you will receive a debugging prompt.
86
+
87
+ ### From the command line
88
+
89
+ If you want to debug a Ruby script without editing it, you can invoke byebug from the command line.
90
+
91
+ ```shell
92
+ byebug myscript.rb
93
+ ```
94
+
95
+ ## Byebug's commands
96
+
97
+ Command | Aliases | Subcommands
98
+ ------- | ------- | -----------
99
+ `backtrace` | `bt` `w` `where`|
100
+ `break` | `b` |
101
+ `catch` | `cat` |
102
+ `condition` | `cond` |
103
+ `continue` | `c` `cont` |
104
+ `debug` | |
105
+ `delete` | `del` |
106
+ `disable` | `dis` | `breakpoints` `display`
107
+ `display` | `disp` |
108
+ `down` | |
109
+ `edit` | `ed` |
110
+ `enable` | `en` | `breakpoints` `display`
111
+ `finish` | `fin` |
112
+ `frame` | `f` |
113
+ `help` | `h` |
114
+ `history` | `hist` |
115
+ `info` | `i` | `args` `breakpoints` `catch` `display` `file` `line` `program`
116
+ `interrupt` | `int` |
117
+ `irb` | |
118
+ `kill` | |
119
+ `list` | `l` |
120
+ `method` | `m` | `instance`
121
+ `next` | `n` |
122
+ `pry` | |
123
+ `quit` | `q` |
124
+ `restart` | |
125
+ `save` | `sa` |
126
+ `set` | | `autoirb` `autolist` `autopry` `autosave` `basename` `callstyle` `fullpath` `histfile` `histsize` `linetrace` `listsize` `post_mortem` `savefile` `stack_on_error` `width`
127
+ `show` | | `autoirb` `autolist` `autopry` `autosave` `basename` `callstyle` `fullpath` `histfile` `histsize` `linetrace` `listsize` `post_mortem` `savefile` `stack_on_error` `width`
128
+ `skip` | `sk` |
129
+ `source` | `so` |
130
+ `step` | `s` |
131
+ `thread` | `th` | `current` `list` `resume` `stop` `switch`
132
+ `tracevar` | `tr` |
133
+ `undisplay` | `undisp` |
134
+ `untracevar`| `untr` |
135
+ `up` | |
136
+ `var` | `v` | `all` `constant` `global` `instance` `local`
137
+
138
+ ## Semantic Versioning
139
+
140
+ Byebug attempts to follow [semantic versioning](https://semver.org) and
141
+ bump major version only when backwards incompatible changes are released.
142
+ Backwards compatibility is targeted to [pry-byebug] and any other plugins
143
+ relying on `byebug`.
144
+
145
+ ## Getting Started
146
+
147
+ Read [byebug's markdown
148
+ guide](https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md) to get
149
+ started. Proper documentation will be eventually written.
150
+
151
+ ## Related projects
152
+
153
+ * [pry-byebug] adds `next`, `step`, `finish`, `continue` and `break` commands
154
+ to `pry` using `byebug`.
155
+ * [ruby-debug-passenger] adds a rake task that restarts Passenger with Byebug
156
+ connected.
157
+ * [minitest-byebug] starts a byebug session on minitest failures.
158
+ * [sublime_debugger] provides a plugin for ruby debugging on Sublime Text.
159
+ * [atom-byebug] provides integration with the Atom editor [EXPERIMENTAL].
160
+
161
+ ## Contribute
162
+
163
+ See [Getting Started with Development](CONTRIBUTING.md).
164
+
165
+ ## Funding
166
+
167
+ Subscribe to [Tidelift] to ensure byebug stays actively maintained, and at the
168
+ same time get licensing assurances and timely security notifications for your
169
+ open source dependencies.
170
+
171
+ You can also help `byebug` by leaving a small (or big) tip through [Liberapay].
172
+
173
+ ## Security contact information
174
+
175
+ Please use the Tidelift security contact to [report a security vulnerability].
176
+ Tidelift will coordinate the fix and disclosure.
177
+
178
+ ## Credits
179
+
180
+ Everybody who has ever contributed to this forked and reforked piece of
181
+ software, especially:
182
+
183
+ * @ko1, author of the awesome TracePoint API for Ruby.
184
+ * @cldwalker, [debugger]'s maintainer.
185
+ * @denofevil, author of [debase], the starting point of this.
186
+ * @kevjames3 for testing, bug reports and the interest in the project.
187
+ * @FooBarWidget for working and helping with remote debugging.
188
+
189
+ [debugger]: https://github.com/cldwalker/debugger
190
+ [pry]: https://github.com/pry/pry
191
+ [debase]: https://github.com/denofevil/debase
192
+ [pry-byebug]: https://github.com/deivid-rodriguez/pry-byebug
193
+ [ruby-debug-passenger]: https://github.com/davejamesmiller/ruby-debug-passenger
194
+ [minitest-byebug]: https://github.com/kaspth/minitest-byebug
195
+ [sublime_debugger]: https://github.com/shuky19/sublime_debugger
196
+ [atom-byebug]: https://github.com/izaera/atom-byebug
197
+ [Liberapay]: https://liberapay.com/byebug/donate
198
+ [Tidelift]: https://tidelift.com/subscription/pkg/rubygems-byebug?utm_source=rubygems-byebug&utm_medium=readme_text
199
+ [report a security vulnerability]: https://tidelift.com/security
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "byebug/runner"
5
+
6
+ Byebug::Runner.new.run
@@ -0,0 +1,517 @@
1
+ #include "byebug.h"
2
+
3
+ #ifdef _WIN32
4
+ #include <ctype.h>
5
+ #endif
6
+
7
+ #if defined DOSISH
8
+ #define isdirsep(x) ((x) == '/' || (x) == '\\')
9
+ #else
10
+ #define isdirsep(x) ((x) == '/')
11
+ #endif
12
+
13
+ static VALUE cBreakpoint;
14
+ static int breakpoint_max;
15
+
16
+ static ID idEval;
17
+
18
+ static VALUE
19
+ eval_expression(VALUE args)
20
+ {
21
+ return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
22
+ }
23
+
24
+ /*
25
+ * call-seq:
26
+ * breakpoint.enabled? -> bool
27
+ *
28
+ * Returns +true+ if breakpoint is enabled, false otherwise.
29
+ */
30
+ static VALUE
31
+ brkpt_enabled(VALUE self)
32
+ {
33
+ breakpoint_t *breakpoint;
34
+
35
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
36
+ return breakpoint->enabled;
37
+ }
38
+
39
+ /*
40
+ * call-seq:
41
+ * breakpoint.enabled = true | false
42
+ *
43
+ * Enables or disables breakpoint.
44
+ */
45
+ static VALUE
46
+ brkpt_set_enabled(VALUE self, VALUE enabled)
47
+ {
48
+ breakpoint_t *breakpoint;
49
+
50
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
51
+ return breakpoint->enabled = enabled;
52
+ }
53
+
54
+ /*
55
+ * call-seq:
56
+ * breakpoint.expr -> string
57
+ *
58
+ * Returns a conditional expression which indicates when this breakpoint should
59
+ * be activated.
60
+ */
61
+ static VALUE
62
+ brkpt_expr(VALUE self)
63
+ {
64
+ breakpoint_t *breakpoint;
65
+
66
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
67
+ return breakpoint->expr;
68
+ }
69
+
70
+ /*
71
+ * call-seq:
72
+ * breakpoint.expr = string | nil
73
+ *
74
+ * Sets or unsets the conditional expression which indicates when this
75
+ * breakpoint should be activated.
76
+ */
77
+ static VALUE
78
+ brkpt_set_expr(VALUE self, VALUE expr)
79
+ {
80
+ breakpoint_t *breakpoint;
81
+
82
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
83
+ breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
84
+ return expr;
85
+ }
86
+
87
+ /*
88
+ * call-seq:
89
+ * breakpoint.hit_condition -> symbol
90
+ *
91
+ * Returns the hit condition of the breakpoint: +nil+ if it is an
92
+ * unconditional breakpoint, or :greater_or_equal, :equal or :modulo otherwise
93
+ */
94
+ static VALUE
95
+ brkpt_hit_condition(VALUE self)
96
+ {
97
+ breakpoint_t *breakpoint;
98
+
99
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
100
+ switch (breakpoint->hit_condition)
101
+ {
102
+ case HIT_COND_GE:
103
+ return ID2SYM(rb_intern("greater_or_equal"));
104
+ case HIT_COND_EQ:
105
+ return ID2SYM(rb_intern("equal"));
106
+ case HIT_COND_MOD:
107
+ return ID2SYM(rb_intern("modulo"));
108
+ case HIT_COND_NONE:
109
+ default:
110
+ return Qnil;
111
+ }
112
+ }
113
+
114
+ /*
115
+ * call-seq:
116
+ * breakpoint.hit_condition = symbol
117
+ *
118
+ * Sets the hit condition of the breakpoint which must be one of the following
119
+ * values:
120
+ *
121
+ * +nil+ if it is an unconditional breakpoint, or
122
+ * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
123
+ */
124
+ static VALUE
125
+ brkpt_set_hit_condition(VALUE self, VALUE value)
126
+ {
127
+ breakpoint_t *breakpoint;
128
+ ID id_value;
129
+
130
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
131
+ id_value = rb_to_id(value);
132
+
133
+ if (rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
134
+ breakpoint->hit_condition = HIT_COND_GE;
135
+ else if (rb_intern("equal") == id_value || rb_intern("eq") == id_value)
136
+ breakpoint->hit_condition = HIT_COND_EQ;
137
+ else if (rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
138
+ breakpoint->hit_condition = HIT_COND_MOD;
139
+ else
140
+ rb_raise(rb_eArgError, "Invalid condition parameter");
141
+ return value;
142
+ }
143
+
144
+ /*
145
+ * call-seq:
146
+ * breakpoint.hit_count -> int
147
+ *
148
+ * Returns the number of times this breakpoint has been hit.
149
+ */
150
+ static VALUE
151
+ brkpt_hit_count(VALUE self)
152
+ {
153
+ breakpoint_t *breakpoint;
154
+
155
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
156
+ return INT2FIX(breakpoint->hit_count);
157
+ }
158
+
159
+ /*
160
+ * call-seq:
161
+ * breakpoint.hit_value -> int
162
+ *
163
+ * Returns the hit value of the breakpoint, namely, a value to build a
164
+ * condition on the number of hits of the breakpoint.
165
+ */
166
+ static VALUE
167
+ brkpt_hit_value(VALUE self)
168
+ {
169
+ breakpoint_t *breakpoint;
170
+
171
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
172
+ return INT2FIX(breakpoint->hit_value);
173
+ }
174
+
175
+ /*
176
+ * call-seq:
177
+ * breakpoint.hit_value = int
178
+ *
179
+ * Sets the hit value of the breakpoint. This allows the user to set conditions
180
+ * on the number of hits to enable/disable the breakpoint.
181
+ */
182
+ static VALUE
183
+ brkpt_set_hit_value(VALUE self, VALUE value)
184
+ {
185
+ breakpoint_t *breakpoint;
186
+
187
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
188
+ breakpoint->hit_value = FIX2INT(value);
189
+ return value;
190
+ }
191
+
192
+ /*
193
+ * call-seq:
194
+ * breakpoint.id -> int
195
+ *
196
+ * Returns the id of the breakpoint.
197
+ */
198
+ static VALUE
199
+ brkpt_id(VALUE self)
200
+ {
201
+ breakpoint_t *breakpoint;
202
+
203
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
204
+ return INT2FIX(breakpoint->id);
205
+ }
206
+
207
+ /*
208
+ * call-seq:
209
+ * breakpoint.pos -> string or int
210
+ *
211
+ * Returns the position of this breakpoint, either a method name or a line
212
+ * number.
213
+ */
214
+ static VALUE
215
+ brkpt_pos(VALUE self)
216
+ {
217
+ breakpoint_t *breakpoint;
218
+
219
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
220
+ if (breakpoint->type == BP_METHOD_TYPE)
221
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
222
+ else
223
+ return INT2FIX(breakpoint->pos.line);
224
+ }
225
+
226
+ /*
227
+ * call-seq:
228
+ * breakpoint.source -> string
229
+ *
230
+ * Returns the source file of the breakpoint.
231
+ */
232
+ static VALUE
233
+ brkpt_source(VALUE self)
234
+ {
235
+ breakpoint_t *breakpoint;
236
+
237
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
238
+ return breakpoint->source;
239
+ }
240
+
241
+ static void
242
+ mark_breakpoint(breakpoint_t *breakpoint)
243
+ {
244
+ rb_gc_mark(breakpoint->source);
245
+ rb_gc_mark(breakpoint->expr);
246
+ }
247
+
248
+ static VALUE
249
+ brkpt_create(VALUE klass)
250
+ {
251
+ breakpoint_t *breakpoint = ALLOC(breakpoint_t);
252
+
253
+ return Data_Wrap_Struct(klass, mark_breakpoint, xfree, breakpoint);
254
+ }
255
+
256
+ static VALUE
257
+ brkpt_initialize(VALUE self, VALUE source, VALUE pos, VALUE expr)
258
+ {
259
+ breakpoint_t *breakpoint;
260
+
261
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
262
+
263
+ breakpoint->type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
264
+ if (breakpoint->type == BP_POS_TYPE)
265
+ breakpoint->pos.line = FIX2INT(pos);
266
+ else
267
+ breakpoint->pos.mid = SYM2ID(pos);
268
+
269
+ breakpoint->id = ++breakpoint_max;
270
+ breakpoint->source = StringValue(source);
271
+ breakpoint->enabled = Qtrue;
272
+ breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
273
+ breakpoint->hit_count = 0;
274
+ breakpoint->hit_value = 0;
275
+ breakpoint->hit_condition = HIT_COND_NONE;
276
+
277
+ return Qnil;
278
+ }
279
+
280
+ static int
281
+ filename_cmp_impl(VALUE source, char *file)
282
+ {
283
+ char *source_ptr, *file_ptr;
284
+ long s_len, f_len, min_len;
285
+ long s, f;
286
+ int dirsep_flag = 0;
287
+
288
+ s_len = RSTRING_LEN(source);
289
+ f_len = strlen(file);
290
+ min_len = s_len < f_len ? s_len : f_len;
291
+
292
+ source_ptr = RSTRING_PTR(source);
293
+ file_ptr = file;
294
+
295
+ for (s = s_len - 1, f = f_len - 1;
296
+ s >= s_len - min_len && f >= f_len - min_len; s--, f--)
297
+ {
298
+ if ((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
299
+ return 1;
300
+ if (isdirsep(source_ptr[s]) && isdirsep(file_ptr[f]))
301
+ dirsep_flag = 1;
302
+ #ifdef DOSISH_DRIVE_LETTER
303
+ else if (s == 0)
304
+ return (toupper(source_ptr[s]) == toupper(file_ptr[f]));
305
+ #endif
306
+ else if (source_ptr[s] != file_ptr[f])
307
+ return 0;
308
+ }
309
+ return 1;
310
+ }
311
+
312
+ static int
313
+ filename_cmp(VALUE source, char *file)
314
+ {
315
+ #ifdef _WIN32
316
+ return filename_cmp_impl(source, file);
317
+ #else
318
+ #ifdef PATH_MAX
319
+ char path[PATH_MAX + 1];
320
+
321
+ path[PATH_MAX] = 0;
322
+ return filename_cmp_impl(source, realpath(file, path) != NULL ? path : file);
323
+ #else
324
+ char *path;
325
+ int result;
326
+
327
+ path = realpath(file, NULL);
328
+ result = filename_cmp_impl(source, path == NULL ? file : path);
329
+ free(path);
330
+ return result;
331
+ #endif
332
+ #endif
333
+ }
334
+
335
+ static int
336
+ classname_cmp(VALUE name, VALUE klass)
337
+ {
338
+ VALUE mod_name;
339
+ VALUE class_name = NIL_P(name) ? rb_str_new2("main") : name;
340
+
341
+ if (NIL_P(klass))
342
+ return 0;
343
+
344
+ mod_name = rb_mod_name(klass);
345
+ return (!NIL_P(mod_name) && rb_str_cmp(class_name, mod_name) == 0);
346
+ }
347
+
348
+ static int
349
+ check_breakpoint_by_hit_condition(VALUE rb_breakpoint)
350
+ {
351
+ breakpoint_t *breakpoint;
352
+
353
+ if (NIL_P(rb_breakpoint))
354
+ return 0;
355
+
356
+ Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
357
+ breakpoint->hit_count++;
358
+
359
+ if (Qtrue != breakpoint->enabled)
360
+ return 0;
361
+
362
+ switch (breakpoint->hit_condition)
363
+ {
364
+ case HIT_COND_NONE:
365
+ return 1;
366
+ case HIT_COND_GE:
367
+ {
368
+ if (breakpoint->hit_count >= breakpoint->hit_value)
369
+ return 1;
370
+ break;
371
+ }
372
+ case HIT_COND_EQ:
373
+ {
374
+ if (breakpoint->hit_count == breakpoint->hit_value)
375
+ return 1;
376
+ break;
377
+ }
378
+ case HIT_COND_MOD:
379
+ {
380
+ if (breakpoint->hit_count % breakpoint->hit_value == 0)
381
+ return 1;
382
+ break;
383
+ }
384
+ }
385
+ return 0;
386
+ }
387
+
388
+ static int
389
+ check_breakpoint_by_pos(VALUE rb_breakpoint, char *file, int line)
390
+ {
391
+ breakpoint_t *breakpoint;
392
+
393
+ if (NIL_P(rb_breakpoint))
394
+ return 0;
395
+
396
+ Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
397
+
398
+ if (Qfalse == breakpoint->enabled || breakpoint->type != BP_POS_TYPE
399
+ || breakpoint->pos.line != line)
400
+ return 0;
401
+
402
+ return filename_cmp(breakpoint->source, file);
403
+ }
404
+
405
+ static int
406
+ check_breakpoint_by_method(VALUE rb_breakpoint, VALUE klass, ID mid, VALUE self)
407
+ {
408
+ breakpoint_t *breakpoint;
409
+
410
+ if (NIL_P(rb_breakpoint))
411
+ return 0;
412
+
413
+ Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
414
+
415
+ if (Qfalse == breakpoint->enabled || breakpoint->type != BP_METHOD_TYPE
416
+ || breakpoint->pos.mid != mid)
417
+ return 0;
418
+
419
+ if (classname_cmp(breakpoint->source, klass)
420
+ || ((rb_type(self) == T_CLASS || rb_type(self) == T_MODULE)
421
+ && classname_cmp(breakpoint->source, self)))
422
+ return 1;
423
+
424
+ return 0;
425
+ }
426
+
427
+ static int
428
+ check_breakpoint_by_expr(VALUE rb_breakpoint, VALUE bind)
429
+ {
430
+ breakpoint_t *breakpoint;
431
+ VALUE args, expr_result;
432
+
433
+ if (NIL_P(rb_breakpoint))
434
+ return 0;
435
+
436
+ Data_Get_Struct(rb_breakpoint, breakpoint_t, breakpoint);
437
+
438
+ if (Qfalse == breakpoint->enabled)
439
+ return 0;
440
+
441
+ if (NIL_P(breakpoint->expr))
442
+ return 1;
443
+
444
+ args = rb_ary_new3(2, breakpoint->expr, bind);
445
+ expr_result = rb_protect(eval_expression, args, 0);
446
+
447
+ return RTEST(expr_result);
448
+ }
449
+
450
+ extern VALUE
451
+ find_breakpoint_by_pos(VALUE breakpoints, VALUE source, VALUE pos, VALUE bind)
452
+ {
453
+ VALUE breakpoint;
454
+ char *file;
455
+ int line;
456
+ int i;
457
+
458
+ file = RSTRING_PTR(source);
459
+ line = FIX2INT(pos);
460
+ for (i = 0; i < RARRAY_LENINT(breakpoints); i++)
461
+ {
462
+ breakpoint = rb_ary_entry(breakpoints, i);
463
+ if (check_breakpoint_by_pos(breakpoint, file, line)
464
+ && check_breakpoint_by_expr(breakpoint, bind)
465
+ && check_breakpoint_by_hit_condition(breakpoint))
466
+ {
467
+ return breakpoint;
468
+ }
469
+ }
470
+ return Qnil;
471
+ }
472
+
473
+ extern VALUE
474
+ find_breakpoint_by_method(VALUE breakpoints, VALUE klass, ID mid, VALUE bind,
475
+ VALUE self)
476
+ {
477
+ VALUE breakpoint;
478
+ int i;
479
+
480
+ for (i = 0; i < RARRAY_LENINT(breakpoints); i++)
481
+ {
482
+ breakpoint = rb_ary_entry(breakpoints, i);
483
+ if (check_breakpoint_by_method(breakpoint, klass, mid, self)
484
+ && check_breakpoint_by_expr(breakpoint, bind)
485
+ && check_breakpoint_by_hit_condition(breakpoint))
486
+ {
487
+ return breakpoint;
488
+ }
489
+ }
490
+ return Qnil;
491
+ }
492
+
493
+ void
494
+ Init_byebug_breakpoint(VALUE mByebug)
495
+ {
496
+ breakpoint_max = 0;
497
+
498
+ cBreakpoint = rb_define_class_under(mByebug, "Breakpoint", rb_cObject);
499
+
500
+ rb_define_alloc_func(cBreakpoint, brkpt_create);
501
+ rb_define_method(cBreakpoint, "initialize", brkpt_initialize, 3);
502
+
503
+ rb_define_method(cBreakpoint, "enabled?", brkpt_enabled, 0);
504
+ rb_define_method(cBreakpoint, "enabled=", brkpt_set_enabled, 1);
505
+ rb_define_method(cBreakpoint, "expr", brkpt_expr, 0);
506
+ rb_define_method(cBreakpoint, "expr=", brkpt_set_expr, 1);
507
+ rb_define_method(cBreakpoint, "hit_count", brkpt_hit_count, 0);
508
+ rb_define_method(cBreakpoint, "hit_condition", brkpt_hit_condition, 0);
509
+ rb_define_method(cBreakpoint, "hit_condition=", brkpt_set_hit_condition, 1);
510
+ rb_define_method(cBreakpoint, "hit_value", brkpt_hit_value, 0);
511
+ rb_define_method(cBreakpoint, "hit_value=", brkpt_set_hit_value, 1);
512
+ rb_define_method(cBreakpoint, "id", brkpt_id, 0);
513
+ rb_define_method(cBreakpoint, "pos", brkpt_pos, 0);
514
+ rb_define_method(cBreakpoint, "source", brkpt_source, 0);
515
+
516
+ idEval = rb_intern("eval");
517
+ }