@@ -171,43 +171,75 @@ parse_version_number(const char *string)
171171 return version ;
172172}
173173
174+ struct sort_context {
175+ VALUE rb_self ;
176+ VALUE rb_version_array ;
177+ compare_callback_t * cmp ;
178+ struct version_number * * versions ;
179+ };
180+
174181static VALUE
175- rb_version_sort_1 (VALUE rb_self , VALUE rb_version_array , compare_callback_t cmp )
182+ rb_version_sort_1_cb (VALUE arg )
176183{
177- struct version_number * * versions ;
184+ struct sort_context * context = ( struct sort_context * ) arg ;
178185 long length , i ;
179186 VALUE * rb_version_ptr ;
180187
181- Check_Type (rb_version_array , T_ARRAY );
182-
183- length = RARRAY_LEN (rb_version_array );
184- if (!length )
185- return rb_ary_new ();
186-
187- versions = xcalloc (length , sizeof (struct version_number * ));
188-
188+ length = RARRAY_LEN (context -> rb_version_array );
189189 for (i = 0 ; i < length ; ++ i ) {
190190 VALUE rb_version , rb_version_string ;
191191
192- rb_version = rb_ary_entry (rb_version_array , i );
192+ rb_version = rb_ary_entry (context -> rb_version_array , i );
193193 if (rb_block_given_p ())
194194 rb_version_string = rb_yield (rb_version );
195195 else
196196 rb_version_string = rb_version ;
197197
198- versions [i ] = parse_version_number (StringValueCStr (rb_version_string ));
199- versions [i ]-> rb_version = rb_version ;
198+ context -> versions [i ] = parse_version_number (StringValueCStr (rb_version_string ));
199+ context -> versions [i ]-> rb_version = rb_version ;
200+ }
201+
202+ qsort (context -> versions , length , sizeof (struct version_number * ), context -> cmp );
203+ rb_version_ptr = RARRAY_PTR (context -> rb_version_array );
204+
205+ for (i = 0 ; i < length ; ++ i ) {
206+ rb_version_ptr [i ] = context -> versions [i ]-> rb_version ;
200207 }
201208
202- qsort (versions , length , sizeof (struct version_number * ), cmp );
203- rb_version_ptr = RARRAY_PTR (rb_version_array );
209+ return context -> rb_version_array ;
210+ }
211+
212+ static VALUE
213+ rb_version_sort_1 (VALUE rb_self , VALUE rb_version_array , compare_callback_t cmp )
214+ {
215+ long length , i ;
216+ int exception ;
217+
218+ Check_Type (rb_version_array , T_ARRAY );
219+
220+ length = RARRAY_LEN (rb_version_array );
221+ if (!length )
222+ return rb_ary_new ();
223+
224+ struct sort_context context = {
225+ rb_self ,
226+ rb_version_array ,
227+ cmp ,
228+ xcalloc (length , sizeof (struct version_number * )),
229+ };
230+
231+ VALUE result = rb_protect (rb_version_sort_1_cb , (VALUE )& context , & exception );
204232
205233 for (i = 0 ; i < length ; ++ i ) {
206- rb_version_ptr [i ] = versions [i ]-> rb_version ;
207- xfree (versions [i ]);
234+ xfree (context .versions [i ]);
208235 }
209- xfree (versions );
210- return rb_version_array ;
236+ xfree (context .versions );
237+
238+ if (exception ) {
239+ rb_jump_tag (exception );
240+ }
241+
242+ return result ;
211243}
212244
213245static VALUE
@@ -234,16 +266,39 @@ rb_version_sort_r_bang(VALUE rb_self, VALUE rb_versions)
234266 return rb_version_sort_1 (rb_self , rb_versions , version_compare_cb_r );
235267}
236268
269+ struct compare_context {
270+ VALUE rb_version_a , rb_version_b ;
271+ struct version_number * version_a , * version_b ;
272+ };
273+
274+ static VALUE
275+ rb_version_compare_cb (VALUE arg )
276+ {
277+ struct compare_context * context = (struct compare_context * )arg ;
278+
279+ context -> version_a = parse_version_number (StringValueCStr (context -> rb_version_a ));
280+ context -> version_b = parse_version_number (StringValueCStr (context -> rb_version_b ));
281+
282+ return INT2NUM (version_compare_cb (& context -> version_a , & context -> version_b ));
283+ }
284+
237285static VALUE
238286rb_version_compare (VALUE rb_self , VALUE rb_version_a , VALUE rb_version_b )
239287{
240- struct version_number * version_a = parse_version_number (StringValueCStr (rb_version_a ));
241- struct version_number * version_b = parse_version_number (StringValueCStr (rb_version_b ));
288+ int exception ;
289+ struct compare_context context = {
290+ rb_version_a , rb_version_b ,
291+ NULL , NULL ,
292+ };
242293
243- VALUE result = INT2NUM ( version_compare_cb ( & version_a , & version_b ) );
294+ VALUE result = rb_protect ( rb_version_compare_cb , ( VALUE ) & context , & exception );
244295
245- xfree (version_a );
246- xfree (version_b );
296+ xfree (context .version_a );
297+ xfree (context .version_b );
298+
299+ if (exception ) {
300+ rb_jump_tag (exception );
301+ }
247302
248303 return result ;
249304}
0 commit comments