byebug 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }