readapt 0.7.1 → 1.1.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.
- checksums.yaml +4 -4
- data/.gitignore +16 -14
- data/.rspec +2 -2
- data/.travis.yml +18 -13
- data/CHANGELOG.md +76 -53
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +37 -29
- data/Rakefile +14 -25
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/exe/readapt +5 -5
- data/ext/readapt/breakpoints.c +83 -88
- data/ext/readapt/breakpoints.h +11 -12
- data/ext/readapt/extconf.rb +0 -0
- data/ext/readapt/frame.c +137 -0
- data/ext/readapt/frame.h +17 -0
- data/ext/readapt/hash_table.c +211 -212
- data/ext/readapt/hash_table.h +30 -32
- data/ext/readapt/inspector.c +51 -0
- data/ext/readapt/inspector.h +8 -0
- data/ext/readapt/monitor.c +40 -27
- data/ext/readapt/monitor.h +0 -0
- data/ext/readapt/normalize.c +59 -53
- data/ext/readapt/normalize.h +7 -7
- data/ext/readapt/readapt.c +18 -16
- data/ext/readapt/stack.c +86 -0
- data/ext/readapt/stack.h +20 -0
- data/ext/readapt/threads.c +111 -17
- data/ext/readapt/threads.h +11 -4
- data/lib/readapt.rb +21 -19
- data/lib/readapt/adapter.rb +98 -138
- data/lib/readapt/breakpoint.rb +20 -13
- data/lib/readapt/data_reader.rb +62 -0
- data/lib/readapt/debugger.rb +220 -204
- data/lib/readapt/error.rb +63 -0
- data/lib/readapt/finder.rb +20 -20
- data/lib/readapt/frame.rb +40 -42
- data/lib/readapt/input.rb +7 -0
- data/lib/readapt/message.rb +62 -59
- data/lib/readapt/message/attach.rb +11 -11
- data/lib/readapt/message/base.rb +32 -32
- data/lib/readapt/message/configuration_done.rb +11 -11
- data/lib/readapt/message/continue.rb +15 -15
- data/lib/readapt/message/disconnect.rb +13 -14
- data/lib/readapt/message/evaluate.rb +18 -18
- data/lib/readapt/message/initialize.rb +13 -13
- data/lib/readapt/message/launch.rb +11 -11
- data/lib/readapt/message/next.rb +12 -12
- data/lib/readapt/message/pause.rb +11 -11
- data/lib/readapt/message/scopes.rb +26 -25
- data/lib/readapt/message/set_breakpoints.rb +25 -25
- data/lib/readapt/message/set_exception_breakpoints.rb +8 -8
- data/lib/readapt/message/stack_trace.rb +38 -26
- data/lib/readapt/message/step_in.rb +11 -11
- data/lib/readapt/message/step_out.rb +11 -11
- data/lib/readapt/message/threads.rb +18 -18
- data/lib/readapt/message/variables.rb +61 -57
- data/lib/readapt/monitor.rb +0 -0
- data/lib/readapt/output.rb +25 -0
- data/lib/readapt/references.rb +27 -0
- data/lib/readapt/server.rb +22 -0
- data/lib/readapt/shell.rb +104 -39
- data/lib/readapt/snapshot.rb +1 -13
- data/lib/readapt/thread.rb +23 -39
- data/lib/readapt/variable.rb +1 -1
- data/lib/readapt/version.rb +3 -3
- data/readapt.gemspec +39 -39
- metadata +19 -8
- data/lib/readapt/location.rb +0 -25
data/ext/readapt/hash_table.h
CHANGED
@@ -1,32 +1,30 @@
|
|
1
|
-
#ifndef HASH_TABLE_H_
|
2
|
-
#define HASH_TABLE_H_
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
void
|
27
|
-
|
28
|
-
void
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
#endif // HASH_TABLE_H_
|
1
|
+
#ifndef HASH_TABLE_H_
|
2
|
+
#define HASH_TABLE_H_
|
3
|
+
|
4
|
+
typedef struct ht_long_array
|
5
|
+
{
|
6
|
+
long *items;
|
7
|
+
long size;
|
8
|
+
} ht_long_array;
|
9
|
+
|
10
|
+
// ht_item is an item in the hash table
|
11
|
+
typedef struct ht_item
|
12
|
+
{
|
13
|
+
char *key;
|
14
|
+
ht_long_array *value;
|
15
|
+
} ht_item;
|
16
|
+
|
17
|
+
typedef struct ht_hash_table
|
18
|
+
{
|
19
|
+
long size;
|
20
|
+
ht_item **items;
|
21
|
+
} ht_hash_table;
|
22
|
+
|
23
|
+
ht_hash_table *ht_new();
|
24
|
+
void ht_del_hash_table(ht_hash_table *ht);
|
25
|
+
|
26
|
+
void ht_insert(ht_hash_table *ht, char *key, const long *value, const long size);
|
27
|
+
ht_long_array *ht_search(ht_hash_table *ht, char *key);
|
28
|
+
void ht_delete(ht_hash_table *h, char *key);
|
29
|
+
|
30
|
+
#endif // HASH_TABLE_H_
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "ruby/debug.h"
|
3
|
+
#include "frame.h"
|
4
|
+
#include "threads.h"
|
5
|
+
#include "normalize.h"
|
6
|
+
|
7
|
+
static VALUE process_inspection(const rb_debug_inspector_t *inspector, void *ptr)
|
8
|
+
{
|
9
|
+
VALUE locations;
|
10
|
+
long i_size;
|
11
|
+
long i;
|
12
|
+
VALUE loc;
|
13
|
+
VALUE path;
|
14
|
+
int line;
|
15
|
+
VALUE bnd;
|
16
|
+
thread_reference_t *data;
|
17
|
+
frame_t *frm;
|
18
|
+
VALUE iseq;
|
19
|
+
|
20
|
+
data = ptr;
|
21
|
+
|
22
|
+
locations = rb_debug_inspector_backtrace_locations(inspector);
|
23
|
+
i_size = locations == Qnil ? 0 : RARRAY_LENINT(locations);
|
24
|
+
for (i = i_size - 1; i >= 0; i--)
|
25
|
+
{
|
26
|
+
iseq = rb_debug_inspector_frame_iseq_get(inspector, i);
|
27
|
+
if (iseq != Qnil)
|
28
|
+
{
|
29
|
+
loc = rb_ary_entry(locations, i);
|
30
|
+
path = rb_funcall(loc, rb_intern("absolute_path"), 0);
|
31
|
+
line = NUM2INT(rb_funcall(loc, rb_intern("lineno"), 0));
|
32
|
+
bnd = rb_debug_inspector_frame_binding_get(inspector, i);
|
33
|
+
|
34
|
+
frm = malloc(sizeof(frame_t));
|
35
|
+
frm->file = normalize_path_new_cstr(StringValueCStr(path));
|
36
|
+
frm->line = line;
|
37
|
+
frm->binding = bnd;
|
38
|
+
stack_push(data->frames, frm);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
return Qnil;
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Get an array of frames from the Ruby debug inspector.
|
47
|
+
*/
|
48
|
+
void inspector_inspect(thread_reference_t *data)
|
49
|
+
{
|
50
|
+
rb_debug_inspector_open(process_inspection, (void *)data);
|
51
|
+
}
|
data/ext/readapt/monitor.c
CHANGED
@@ -46,18 +46,16 @@ static int match_step(thread_reference_t *ptr)
|
|
46
46
|
static ID
|
47
47
|
monitor_debug(const char *file, const long line, VALUE tracepoint, thread_reference_t *ptr, ID event)
|
48
48
|
{
|
49
|
-
VALUE
|
49
|
+
VALUE snapshot, result, gc_disabled;
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
// Disable garbage collection to avoid segfaults in Frame#frame_binding
|
52
|
+
gc_disabled = rb_gc_disable();
|
53
|
+
thread_reference_build_frames(ptr);
|
54
|
+
snapshot = rb_funcall(c_Snapshot, rb_intern("new"), 4,
|
55
|
+
INT2NUM(ptr->id),
|
56
56
|
rb_str_new_cstr(file),
|
57
57
|
INT2NUM(line),
|
58
|
-
|
59
|
-
ID2SYM(event),
|
60
|
-
INT2NUM(ptr->depth)
|
58
|
+
ID2SYM(event)
|
61
59
|
);
|
62
60
|
rb_io_flush(rb_stdout);
|
63
61
|
rb_io_flush(rb_stderr);
|
@@ -68,33 +66,44 @@ monitor_debug(const char *file, const long line, VALUE tracepoint, thread_refere
|
|
68
66
|
ptr->cursor = ptr->depth;
|
69
67
|
ptr->control = result;
|
70
68
|
}
|
69
|
+
thread_reference_clear_frames(ptr);
|
70
|
+
if (!RTEST(gc_disabled))
|
71
|
+
{
|
72
|
+
rb_gc_enable();
|
73
|
+
}
|
71
74
|
return result;
|
72
75
|
}
|
73
76
|
|
74
77
|
static void
|
75
78
|
process_line_event(VALUE tracepoint, void *data)
|
76
79
|
{
|
77
|
-
VALUE ref
|
78
|
-
char *tp_file;
|
79
|
-
long tp_line;
|
80
|
+
VALUE ref;
|
80
81
|
thread_reference_t *ptr;
|
81
|
-
rb_trace_arg_t *
|
82
|
+
rb_trace_arg_t *arg;
|
82
83
|
int threadPaused;
|
83
84
|
ID dapEvent;
|
85
|
+
VALUE tmp;
|
86
|
+
char *tp_file;
|
87
|
+
long tp_line;
|
84
88
|
|
85
89
|
ref = thread_current_reference();
|
86
90
|
if (ref != Qnil)
|
87
91
|
{
|
88
92
|
ptr = thread_reference_pointer(ref);
|
89
93
|
threadPaused = (ptr->control == id_pause);
|
94
|
+
|
90
95
|
if (firstLineEvent && ptr->control == id_continue && breakpoints_files() == 0)
|
91
96
|
{
|
92
97
|
return;
|
93
98
|
}
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
99
|
+
|
100
|
+
arg = rb_tracearg_from_tracepoint(tracepoint);
|
101
|
+
tmp = rb_tracearg_path(arg);
|
102
|
+
// tp_file = normalize_path_new_cstr(StringValueCStr(tmp));
|
103
|
+
tp_file = StringValueCStr(tmp);
|
104
|
+
normalize_path(tp_file);
|
105
|
+
tmp = rb_tracearg_lineno(arg);
|
106
|
+
tp_line = NUM2INT(tmp);
|
98
107
|
|
99
108
|
dapEvent = id_continue;
|
100
109
|
if (!firstLineEvent)
|
@@ -128,7 +137,7 @@ process_line_event(VALUE tracepoint, void *data)
|
|
128
137
|
monitor_debug(tp_file, tp_line, tracepoint, ptr, dapEvent);
|
129
138
|
}
|
130
139
|
|
131
|
-
free(tp_file);
|
140
|
+
// free(tp_file);
|
132
141
|
}
|
133
142
|
}
|
134
143
|
|
@@ -163,7 +172,7 @@ process_return_event(VALUE tracepoint, void *data)
|
|
163
172
|
static void
|
164
173
|
process_thread_begin_event(VALUE tracepoint, void *data)
|
165
174
|
{
|
166
|
-
VALUE list, here,
|
175
|
+
VALUE list, here, ref;
|
167
176
|
thread_reference_t *ptr;
|
168
177
|
|
169
178
|
list = rb_funcall(rb_cThread, rb_intern("list"), 0);
|
@@ -189,12 +198,15 @@ process_thread_end_event(VALUE tracepoint, void *data)
|
|
189
198
|
thread_reference_t *ptr;
|
190
199
|
|
191
200
|
thr = rb_thread_current();
|
192
|
-
|
193
|
-
if (ref != Qnil)
|
201
|
+
if (thr != Qnil)
|
194
202
|
{
|
195
|
-
|
196
|
-
|
197
|
-
|
203
|
+
ref = thread_reference(thr);
|
204
|
+
if (ref != Qnil)
|
205
|
+
{
|
206
|
+
ptr = thread_reference_pointer(ref);
|
207
|
+
monitor_debug("", 0, tracepoint, ptr, rb_intern("thread_end"));
|
208
|
+
thread_delete_reference(thr);
|
209
|
+
}
|
198
210
|
}
|
199
211
|
}
|
200
212
|
|
@@ -255,6 +267,7 @@ monitor_disable_s(VALUE self)
|
|
255
267
|
|
256
268
|
free(entryFile);
|
257
269
|
entryFile = NULL;
|
270
|
+
thread_clear();
|
258
271
|
|
259
272
|
return previous;
|
260
273
|
}
|
@@ -280,15 +293,15 @@ void initialize_monitor(VALUE m_Readapt)
|
|
280
293
|
m_Monitor = rb_define_module_under(m_Readapt, "Monitor");
|
281
294
|
c_Snapshot = rb_define_class_under(m_Readapt, "Snapshot", rb_cObject);
|
282
295
|
|
283
|
-
initialize_threads();
|
296
|
+
initialize_threads(m_Readapt);
|
284
297
|
|
285
298
|
rb_define_singleton_method(m_Monitor, "start", monitor_enable_s, 1);
|
286
299
|
rb_define_singleton_method(m_Monitor, "stop", monitor_disable_s, 0);
|
287
300
|
rb_define_singleton_method(m_Monitor, "pause", monitor_pause_s, 1);
|
288
301
|
|
289
302
|
tpLine = rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, process_line_event, NULL);
|
290
|
-
tpCall = rb_tracepoint_new(Qnil, RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS, process_call_event, NULL);
|
291
|
-
tpReturn = rb_tracepoint_new(Qnil, RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END, process_return_event, NULL);
|
303
|
+
tpCall = rb_tracepoint_new(Qnil, RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS | RUBY_EVENT_C_CALL, process_call_event, NULL);
|
304
|
+
tpReturn = rb_tracepoint_new(Qnil, RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END | RUBY_EVENT_C_RETURN, process_return_event, NULL);
|
292
305
|
tpThreadBegin = rb_tracepoint_new(Qnil, RUBY_EVENT_THREAD_BEGIN, process_thread_begin_event, NULL);
|
293
306
|
tpThreadEnd = rb_tracepoint_new(Qnil, RUBY_EVENT_THREAD_END, process_thread_end_event, NULL);
|
294
307
|
debugProc = Qnil;
|
data/ext/readapt/monitor.h
CHANGED
File without changes
|
data/ext/readapt/normalize.c
CHANGED
@@ -1,53 +1,59 @@
|
|
1
|
-
#include "ruby.h"
|
2
|
-
#include "ruby/debug.h"
|
3
|
-
#include <ctype.h>
|
4
|
-
|
5
|
-
static int isWindows;
|
6
|
-
|
7
|
-
static int
|
8
|
-
checkIfWindows()
|
9
|
-
{
|
10
|
-
VALUE regexp, result;
|
11
|
-
|
12
|
-
regexp = rb_reg_new("/cygwin|mswin|mingw|bccwin|wince|emx/", 37, 0);
|
13
|
-
result = rb_reg_match(regexp, rb_str_new_cstr(RUBY_PLATFORM));
|
14
|
-
return result == Qnil ? 0 : 1;
|
15
|
-
}
|
16
|
-
|
17
|
-
|
18
|
-
{
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "ruby/debug.h"
|
3
|
+
#include <ctype.h>
|
4
|
+
|
5
|
+
static int isWindows;
|
6
|
+
|
7
|
+
static int
|
8
|
+
checkIfWindows()
|
9
|
+
{
|
10
|
+
VALUE regexp, result;
|
11
|
+
|
12
|
+
regexp = rb_reg_new("/cygwin|mswin|mingw|bccwin|wince|emx/", 37, 0);
|
13
|
+
result = rb_reg_match(regexp, rb_str_new_cstr(RUBY_PLATFORM));
|
14
|
+
return result == Qnil ? 0 : 1;
|
15
|
+
}
|
16
|
+
|
17
|
+
void normalize_path(char *str)
|
18
|
+
{
|
19
|
+
long i, len;
|
20
|
+
|
21
|
+
if (isWindows)
|
22
|
+
{
|
23
|
+
str[0] = toupper(str[0]);
|
24
|
+
len = strlen(str);
|
25
|
+
for (i = 2; i < len; i++)
|
26
|
+
{
|
27
|
+
if (str[i] == '\\')
|
28
|
+
{
|
29
|
+
str[i] = '/';
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
char *normalize_path_new_cstr(char *str)
|
36
|
+
{
|
37
|
+
char *buffer;
|
38
|
+
|
39
|
+
buffer = malloc((strlen(str) + 1) * sizeof(char));
|
40
|
+
strcpy(buffer, str);
|
41
|
+
normalize_path(buffer);
|
42
|
+
return buffer;
|
43
|
+
}
|
44
|
+
|
45
|
+
static VALUE
|
46
|
+
normalize_path_s(VALUE self, VALUE str)
|
47
|
+
{
|
48
|
+
char *path = normalize_path_new_cstr(StringValueCStr(str));
|
49
|
+
VALUE result = rb_str_new_cstr(path);
|
50
|
+
free(path);
|
51
|
+
return result;
|
52
|
+
}
|
53
|
+
|
54
|
+
void initialize_normalize(VALUE m_Readapt)
|
55
|
+
{
|
56
|
+
isWindows = checkIfWindows();
|
57
|
+
|
58
|
+
rb_define_singleton_method(m_Readapt, "normalize_path", normalize_path_s, 1);
|
59
|
+
}
|
data/ext/readapt/normalize.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
#ifndef NORMALIZE_H_
|
2
|
-
#define NORMALIZE_H_
|
3
|
-
|
4
|
-
void initialize_normalize(VALUE);
|
5
|
-
char *normalize_path_new_cstr(char *str);
|
6
|
-
|
7
|
-
#endif
|
1
|
+
#ifndef NORMALIZE_H_
|
2
|
+
#define NORMALIZE_H_
|
3
|
+
|
4
|
+
void initialize_normalize(VALUE);
|
5
|
+
char *normalize_path_new_cstr(char *str);
|
6
|
+
void normalize_path(char *str);
|
7
|
+
#endif
|
data/ext/readapt/readapt.c
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
#include "ruby.h"
|
2
|
-
#include "ruby/debug.h"
|
3
|
-
#include "monitor.h"
|
4
|
-
#include "normalize.h"
|
5
|
-
#include "breakpoints.h"
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "ruby/debug.h"
|
3
|
+
#include "monitor.h"
|
4
|
+
#include "normalize.h"
|
5
|
+
#include "breakpoints.h"
|
6
|
+
#include "frame.h"
|
7
|
+
|
8
|
+
static VALUE m_Readapt;
|
9
|
+
|
10
|
+
void Init_readapt()
|
11
|
+
{
|
12
|
+
m_Readapt = rb_define_module("Readapt");
|
13
|
+
|
14
|
+
initialize_normalize(m_Readapt);
|
15
|
+
initialize_breakpoints(m_Readapt);
|
16
|
+
initialize_frame(m_Readapt);
|
17
|
+
initialize_monitor(m_Readapt);
|
18
|
+
}
|
data/ext/readapt/stack.c
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include "stack.h"
|
3
|
+
|
4
|
+
#define STACK_CAPACITY 20
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Allocate a stack. The `elem_size` is the expected size of each element,
|
8
|
+
* e.g., `sizeof(some_struct)`. The optional `free_func` argument is a pointer
|
9
|
+
* to a function that will be called when an element is popped off the stack.
|
10
|
+
*/
|
11
|
+
readapt_stack_t *stack_alloc(size_t elem_size, void (*free_func)(void *))
|
12
|
+
{
|
13
|
+
readapt_stack_t *s = malloc(sizeof(readapt_stack_t));
|
14
|
+
s->elem_size = elem_size;
|
15
|
+
s->free_func = free_func;
|
16
|
+
s->size = 0;
|
17
|
+
s->capacity = 0;
|
18
|
+
return s;
|
19
|
+
}
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Add an element to the end of the stack
|
23
|
+
*/
|
24
|
+
void stack_push(readapt_stack_t *stack, void *element)
|
25
|
+
{
|
26
|
+
if (stack->size == stack->capacity)
|
27
|
+
{
|
28
|
+
if (stack->capacity == 0)
|
29
|
+
{
|
30
|
+
stack->capacity = STACK_CAPACITY;
|
31
|
+
stack->elements = malloc(stack->elem_size * stack->capacity);
|
32
|
+
}
|
33
|
+
else
|
34
|
+
{
|
35
|
+
stack->capacity += STACK_CAPACITY;
|
36
|
+
stack->elements = realloc(stack->elements, stack->elem_size * stack->capacity);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
stack->elements[stack->size] = element;
|
40
|
+
stack->size++;
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Get a pointer to the last element in the stack.
|
45
|
+
*/
|
46
|
+
void *stack_peek(readapt_stack_t *stack)
|
47
|
+
{
|
48
|
+
return stack->size == 0 ? NULL : stack->elements[stack->size - 1];
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* Pop the last element off the stack and pass it to free_func.
|
53
|
+
*/
|
54
|
+
void stack_pop(readapt_stack_t *stack)
|
55
|
+
{
|
56
|
+
void *e;
|
57
|
+
|
58
|
+
if (stack->size > 0)
|
59
|
+
{
|
60
|
+
e = stack->elements[stack->size - 1];
|
61
|
+
if (stack->free_func)
|
62
|
+
{
|
63
|
+
stack->free_func(e);
|
64
|
+
}
|
65
|
+
// stack->elements[stack->size - 1] = NULL;
|
66
|
+
stack->size--;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Free the stack from memory. If it still contains any elements, pass them to
|
72
|
+
* free_func.
|
73
|
+
*/
|
74
|
+
void stack_free(readapt_stack_t *stack)
|
75
|
+
{
|
76
|
+
int i;
|
77
|
+
|
78
|
+
if (stack->free_func)
|
79
|
+
{
|
80
|
+
for (i = 0; i < stack->size; i++)
|
81
|
+
{
|
82
|
+
stack->free_func(stack->elements[i]);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
free(stack);
|
86
|
+
}
|