1 /*
2  * swigutil_pl.c: utility functions for the SWIG Perl bindings
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23 
24 #include <apr.h>
25 #include <apr_general.h>
26 #include <apr_portable.h>
27 
28 /* Windows hack: Allow overriding some <perl.h> defaults */
29 #include "swigutil_pl__pre_perl.h"
30 
31 #include <EXTERN.h>
32 #include <perl.h>
33 #include <XSUB.h>
34 
35 /* Perl defines a _ macro, but SVN uses it for translations.
36  * So undefine _ after including the Perl headers. */
37 #undef _
38 
39 #include <stdarg.h>
40 #ifdef WIN32
41 #include <io.h>
42 #endif
43 
44 #include "svn_hash.h"
45 #include "svn_pools.h"
46 #include "svn_opt.h"
47 #include "svn_time.h"
48 #include "svn_private_config.h"
49 
50 #include "swig_perl_external_runtime.swg"
51 
52 #include "swigutil_pl.h"
53 
54 /* cache SWIG_TypeQuery results in a perl hash */
55 static HV *type_cache = NULL;
56 
57 #define _SWIG_TYPE(name) _swig_perl_type_query(name, 0)
58 #define POOLINFO         _SWIG_TYPE("apr_pool_t *")
59 
_swig_perl_type_query(const char * type_name,U32 klen)60 static swig_type_info *_swig_perl_type_query(const char *type_name, U32 klen)
61 {
62     SV **type_info;
63     swig_type_info *tinfo;
64 
65     if (!type_cache)
66       type_cache = newHV();
67 
68     if (klen == 0)
69       klen = strlen(type_name);
70 
71     if ((type_info = hv_fetch(type_cache, type_name, klen, 0)))
72       return (swig_type_info *) (SvIV(*type_info));
73 
74     tinfo = SWIG_TypeQuery(type_name);
75     hv_store(type_cache, type_name, klen, newSViv((IV)tinfo), 0);
76 
77     return tinfo;
78 }
79 
80 /* element convertors for perl -> c */
81 typedef void *(*pl_element_converter_t)(SV *value, void *ctx,
82                                         apr_pool_t *pool);
83 
convert_pl_string(SV * value,void * dummy,apr_pool_t * pool)84 static void *convert_pl_string(SV *value, void *dummy, apr_pool_t *pool)
85 {
86     void **result = apr_palloc(pool, sizeof(void *));
87     *result = SvPV_nolen(value);
88     return *result;
89 }
90 
convert_pl_obj(SV * value,swig_type_info * tinfo,apr_pool_t * pool)91 static void *convert_pl_obj(SV *value, swig_type_info *tinfo,
92                             apr_pool_t *pool)
93 {
94     void **result = apr_palloc(pool, sizeof(void *));
95     if (SWIG_ConvertPtr(value, result, tinfo, 0) < 0) {
96         croak("unable to convert from swig object");
97     }
98     return *result;
99 }
100 
convert_pl_revnum_t(SV * value,void * dummy,apr_pool_t * pool)101 static void *convert_pl_revnum_t(SV *value, void *dummy, apr_pool_t *pool)
102 {
103   svn_revnum_t *result = apr_palloc(pool, sizeof(svn_revnum_t));
104   *result = SvIV(value);
105   return (void *)result;
106 }
107 
convert_pl_svn_string_t(SV * value,void * dummy,apr_pool_t * pool)108 static void *convert_pl_svn_string_t(SV *value, void *dummy, apr_pool_t *pool)
109 {
110     svn_string_t *result = apr_palloc(pool, sizeof(svn_string_t));
111     /* just the in typemap for svn_string_t */
112     result->data = SvPV(value, result->len);
113     return (void *)result;
114 }
115 
116 /* Convert a revision range and return a svn_opt_revision_range_t*.
117  * Value can be:
118  * - a _p_svn_opt_revision_range_t object
119  * - a reference to a two-element array, [start, end],
120  *   where start and end is anything accepted by svn_swig_pl_set_revision
121  * If value is not acceptable and *(svn_boolean_t *)ctx is FALSE,
122  * convert_pl_revision_range returns NULL, otherwise it croak()s.
123  */
convert_pl_revision_range(SV * value,void * ctx,apr_pool_t * pool)124 static void *convert_pl_revision_range(SV *value, void *ctx, apr_pool_t *pool)
125 {
126     svn_boolean_t croak_on_error = *(svn_boolean_t *)ctx;
127 
128     if (sv_isobject(value) && sv_derived_from(value, "_p_svn_opt_revision_range_t")) {
129         svn_opt_revision_range_t *range;
130         /* this will assign to range */
131         SWIG_ConvertPtr(value, (void **)&range, _SWIG_TYPE("svn_opt_revision_range_t *"), 0);
132         return range;
133     }
134 
135     if (SvROK(value)
136         && SvTYPE(SvRV(value)) == SVt_PVAV
137         && av_len((AV *)SvRV(value)) == 1) {
138         /* value is a two-element ARRAY */
139         AV* array = (AV *)SvRV(value);
140         svn_opt_revision_t temp_start, temp_end;
141         svn_opt_revision_t *start, *end;
142         svn_opt_revision_range_t *range;
143 
144         /* Note: Due to how svn_swig_pl_set_revision works,
145          * either the passed in svn_opt_revision_t is modified
146          * (and the original pointer returned) or a different pointer
147          * is returned. svn_swig_pl_set_revision may return NULL
148          * only if croak_on_error is FALSE.
149          */
150         start = svn_swig_pl_set_revision(&temp_start,
151                                          *av_fetch(array, 0, 0),
152                                          croak_on_error, pool);
153         if (start == NULL)
154             return NULL;
155         end = svn_swig_pl_set_revision(&temp_end,
156                                        *av_fetch(array, 1, 0),
157                                        croak_on_error, pool);
158         if (end == NULL)
159             return NULL;
160 
161         /* allocate a new range and copy in start and end fields */
162         range = apr_palloc(pool, sizeof(*range));
163         range->start = *start;
164         range->end = *end;
165         return range;
166     }
167 
168     if (croak_on_error)
169         croak("unknown revision range: "
170               "must be an array of length 2 whose elements are acceptable "
171               "as opt_revision_t or a _p_svn_opt_revision_range_t object");
172     return NULL;
173 }
174 
175 /* perl -> c hash convertors */
svn_swig_pl_to_hash(SV * source,pl_element_converter_t cv,void * ctx,apr_pool_t * pool)176 static apr_hash_t *svn_swig_pl_to_hash(SV *source,
177                                        pl_element_converter_t cv,
178                                        void *ctx, apr_pool_t *pool)
179 {
180     apr_hash_t *hash;
181     HV *h;
182     char *key;
183     I32 cnt, retlen;
184 
185     if (!(source && SvROK(source) && SvTYPE(SvRV(source)) == SVt_PVHV)) {
186         return NULL;
187     }
188 
189     hash = apr_hash_make(pool);
190     h = (HV *)SvRV(source);
191     cnt = hv_iterinit(h);
192     while (cnt--) {
193         SV* item = hv_iternextsv(h, &key, &retlen);
194         void *val = cv(item, ctx, pool);
195         svn_hash_sets(hash, apr_pstrmemdup(pool, key, retlen), val);
196     }
197 
198     return hash;
199 }
200 
svn_swig_pl_objs_to_hash(SV * source,swig_type_info * tinfo,apr_pool_t * pool)201 apr_hash_t *svn_swig_pl_objs_to_hash(SV *source, swig_type_info *tinfo,
202                                      apr_pool_t *pool)
203 {
204 
205     return svn_swig_pl_to_hash(source, (pl_element_converter_t)convert_pl_obj,
206                                tinfo, pool);
207 }
208 
svn_swig_pl_strings_to_hash(SV * source,apr_pool_t * pool)209 apr_hash_t *svn_swig_pl_strings_to_hash(SV *source, apr_pool_t *pool)
210 {
211 
212     return svn_swig_pl_to_hash(source, convert_pl_string, NULL, pool);
213 }
214 
215 
svn_swig_pl_objs_to_hash_by_name(SV * source,const char * typename,apr_pool_t * pool)216 apr_hash_t *svn_swig_pl_objs_to_hash_by_name(SV *source,
217                                              const char *typename,
218                                              apr_pool_t *pool)
219 {
220     swig_type_info *tinfo = _SWIG_TYPE(typename);
221     return svn_swig_pl_objs_to_hash(source, tinfo, pool);
222 }
223 
svn_swig_pl_objs_to_hash_of_revnum_t(SV * source,apr_pool_t * pool)224 apr_hash_t *svn_swig_pl_objs_to_hash_of_revnum_t(SV *source,
225                                                  apr_pool_t *pool)
226 {
227 
228   return svn_swig_pl_to_hash(source,
229                              (pl_element_converter_t)convert_pl_revnum_t,
230                              NULL, pool);
231 }
232 
svn_swig_pl_hash_to_prophash(SV * source,apr_pool_t * pool)233 apr_hash_t *svn_swig_pl_hash_to_prophash(SV *source, apr_pool_t *pool)
234 {
235   return svn_swig_pl_to_hash(source, convert_pl_svn_string_t, NULL, pool);
236 }
237 
238 /* perl -> c array convertors */
svn_swig_pl_to_array(SV * source,pl_element_converter_t cv,void * ctx,apr_pool_t * pool)239 static apr_array_header_t *svn_swig_pl_to_array(SV *source,
240                                                 pl_element_converter_t cv,
241                                                 void *ctx, apr_pool_t *pool)
242 {
243     int targlen;
244     apr_array_header_t *temp;
245     AV* array;
246 
247     if (SvROK(source) && SvTYPE(SvRV(source)) == SVt_PVAV) {
248       array = (AV *)SvRV(source);
249       targlen = av_len(array) + 1;
250       temp = apr_array_make(pool, targlen, sizeof(const char *));
251         temp->nelts = targlen;
252 
253         while (targlen--) {
254             /* more error handling here */
255           SV **item = av_fetch(array, targlen, 0);
256           APR_ARRAY_IDX(temp, targlen, const char *) = cv(*item, ctx, pool);
257         }
258     } else if (SvOK(source)) {
259         targlen = 1;
260         temp = apr_array_make(pool, targlen, sizeof(const char *));
261         temp->nelts = targlen;
262         APR_ARRAY_IDX(temp, 0, const char *) = cv(source, ctx, pool);
263     } else {
264         croak("Must pass a single value or an array reference");
265     }
266 
267     return temp;
268 }
269 
svn_swig_pl_strings_to_array(SV * source,apr_pool_t * pool)270 apr_array_header_t *svn_swig_pl_strings_to_array(SV *source,
271                                                        apr_pool_t *pool)
272 {
273   return svn_swig_pl_to_array(source, convert_pl_string, NULL, pool);
274 }
275 
svn_swig_pl_objs_to_array(SV * source,swig_type_info * tinfo,apr_pool_t * pool)276 apr_array_header_t *svn_swig_pl_objs_to_array(SV *source,
277                                               swig_type_info *tinfo,
278                                               apr_pool_t *pool)
279 {
280   return svn_swig_pl_to_array(source,
281                               (pl_element_converter_t)convert_pl_obj,
282                               tinfo, pool);
283 }
284 
285 /* Convert a single revision range or an array of revisions ranges
286  * Note: We can't simply use svn_swig_pl_to_array() as is, since
287  * it immediatley checks whether source is an array reference and then
288  * proceeds to treat this as the "array of ..." case. But a revision range
289  * may be specified as a (two-element) array. Hence we first try to
290  * convert source as a single revision range. Failing that and if it's
291  * an array we then call svn_swig_pl_to_array(). Otherwise we croak().
292  */
svn_swig_pl_array_to_apr_array_revision_range(SV * source,apr_pool_t * pool)293 apr_array_header_t *svn_swig_pl_array_to_apr_array_revision_range(
294         SV *source, apr_pool_t *pool)
295 {
296     svn_boolean_t croak_on_error = FALSE;
297     svn_opt_revision_range_t *range;
298 
299     if ((range = convert_pl_revision_range(source, &croak_on_error, pool))) {
300         apr_array_header_t *temp = apr_array_make(pool, 1,
301                                                   sizeof(svn_opt_revision_range_t *));
302         temp->nelts = 1;
303         APR_ARRAY_IDX(temp, 0, svn_opt_revision_range_t *) = range;
304         return temp;
305     }
306 
307     if (SvROK(source) && SvTYPE(SvRV(source)) == SVt_PVAV) {
308         croak_on_error = TRUE;
309         return svn_swig_pl_to_array(source, convert_pl_revision_range,
310                                     &croak_on_error, pool);
311     }
312 
313     croak("must pass a single revision range or a reference to an array of revision ranges");
314 
315     /* This return is actually unreachable because of the croak above,
316      * however, Visual Studio's compiler doesn't like if all paths don't have
317      * a return and errors out otherwise. */
318     return NULL;
319 }
320 
321 /* element convertors for c -> perl */
322 typedef SV *(*element_converter_t)(void *value, void *ctx);
323 
convert_string(const char * value,void * dummy)324 static SV *convert_string(const char *value, void *dummy)
325 {
326     SV *obj = sv_2mortal(newSVpv(value, 0));
327     return obj;
328 }
329 
convert_svn_string_t(svn_string_t * value,void * dummy)330 static SV *convert_svn_string_t(svn_string_t *value, void *dummy)
331 {
332     SV *obj = sv_2mortal(newSVpv(value->data, value->len));
333     return obj;
334 }
335 
convert_to_swig_type(void * ptr,swig_type_info * tinfo)336 static SV *convert_to_swig_type(void *ptr, swig_type_info *tinfo)
337 {
338     SV *obj = sv_newmortal();
339     SWIG_MakePtr(obj, ptr, tinfo, 0);
340     return obj;
341 }
342 
convert_int(int value,void * dummy)343 static SV *convert_int(int value, void *dummy)
344 {
345   return sv_2mortal(newSViv(value));
346 }
347 
convert_svn_revnum_t(svn_revnum_t revnum,void * dummy)348 static SV *convert_svn_revnum_t(svn_revnum_t revnum, void *dummy)
349 {
350   return sv_2mortal(newSViv((long int)revnum));
351 
352 }
353 
354 /* c -> perl hash convertors */
convert_hash(apr_hash_t * hash,element_converter_t converter_func,void * ctx)355 static SV *convert_hash(apr_hash_t *hash, element_converter_t converter_func,
356                         void *ctx)
357 {
358     apr_hash_index_t *hi;
359     HV *hv;
360 
361     hv = newHV();
362     for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi)) {
363         const char *key;
364         void *val;
365         int klen;
366         SV *obj;
367 
368         apr_hash_this(hi, (void *)&key, NULL, &val);
369         klen = strlen(key);
370 
371         obj = converter_func(val, ctx);
372         hv_store(hv, (const char *)key, klen, obj, 0);
373         SvREFCNT_inc(obj);
374     }
375 
376     return sv_2mortal(newRV_noinc((SV*)hv));
377 }
378 
svn_swig_pl_prophash_to_hash(apr_hash_t * hash)379 SV *svn_swig_pl_prophash_to_hash(apr_hash_t *hash)
380 {
381   return convert_hash(hash, (element_converter_t)convert_svn_string_t,
382                       NULL);
383 }
384 
svn_swig_pl_convert_hash(apr_hash_t * hash,swig_type_info * tinfo)385 SV *svn_swig_pl_convert_hash(apr_hash_t *hash, swig_type_info *tinfo)
386 {
387   return convert_hash(hash, (element_converter_t)convert_to_swig_type,
388                       tinfo);
389 }
390 
391 /* c -> perl array convertors */
convert_array(const apr_array_header_t * array,element_converter_t converter_func,void * ctx)392 static SV *convert_array(const apr_array_header_t *array,
393                   element_converter_t converter_func, void *ctx)
394 {
395     AV *list = newAV();
396     int i;
397 
398     for (i = 0; i < array->nelts; ++i) {
399         void *element = APR_ARRAY_IDX(array, i, void *);
400         SV *item = converter_func(element, ctx);
401         av_push(list, item);
402         SvREFCNT_inc(item);
403     }
404     return sv_2mortal(newRV_noinc((SV*)list));
405 }
406 
svn_swig_pl_array_to_list(const apr_array_header_t * array)407 SV *svn_swig_pl_array_to_list(const apr_array_header_t *array)
408 {
409   return convert_array(array, (element_converter_t)convert_string, NULL);
410 }
411 
412 /* Formerly used by pre-1.0 APIs. Now unused
413 SV *svn_swig_pl_ints_to_list(const apr_array_header_t *array)
414 {
415     return convert_array (array, (element_converter_t)convert_int, NULL);
416 }
417 */
418 
svn_swig_pl_convert_array(const apr_array_header_t * array,swig_type_info * tinfo)419 SV *svn_swig_pl_convert_array(const apr_array_header_t *array,
420                               swig_type_info *tinfo)
421 {
422   return convert_array(array, (element_converter_t)convert_to_swig_type,
423                        tinfo);
424 }
425 
svn_swig_pl_revnums_to_list(const apr_array_header_t * array)426 SV *svn_swig_pl_revnums_to_list(const apr_array_header_t *array)
427 {
428     return convert_array(array, (element_converter_t)convert_svn_revnum_t,
429                          NULL);
430 }
431 
432 /* perl -> c svn_opt_revision_t conversion */
svn_swig_pl_set_revision(svn_opt_revision_t * rev,SV * source,svn_boolean_t croak_on_error,apr_pool_t * pool)433 svn_opt_revision_t *svn_swig_pl_set_revision(svn_opt_revision_t *rev,
434                                              SV *source,
435                                              svn_boolean_t croak_on_error,
436                                              apr_pool_t *pool)
437 {
438 #define maybe_croak(argv) do { if (croak_on_error) croak argv; \
439                                else return NULL; } while (0)
440 
441     if (source == NULL || source == &PL_sv_undef || !SvOK(source)) {
442         rev->kind = svn_opt_revision_unspecified;
443     }
444     else if (sv_isobject(source) && sv_derived_from(source, "_p_svn_opt_revision_t")) {
445         /* this will assign to rev */
446         SWIG_ConvertPtr(source, (void **)&rev, _SWIG_TYPE("svn_opt_revision_t *"), 0);
447     }
448     else if (looks_like_number(source)) {
449         rev->kind = svn_opt_revision_number;
450         rev->value.number = SvIV(source);
451     }
452     else if (SvPOK(source)) {
453         char *input = SvPV_nolen(source);
454         if (svn_cstring_casecmp(input, "BASE") == 0)
455             rev->kind = svn_opt_revision_base;
456         else if (svn_cstring_casecmp(input, "HEAD") == 0)
457             rev->kind = svn_opt_revision_head;
458         else if (svn_cstring_casecmp(input, "WORKING") == 0)
459             rev->kind = svn_opt_revision_working;
460         else if (svn_cstring_casecmp(input, "COMMITTED") == 0)
461             rev->kind = svn_opt_revision_committed;
462         else if (svn_cstring_casecmp(input, "PREV") == 0)
463             rev->kind = svn_opt_revision_previous;
464         else if (*input == '{') {
465             svn_boolean_t matched;
466             apr_time_t tm;
467             svn_error_t *err;
468 
469             char *end = strchr(input,'}');
470             char saved_end;
471             if (!end)
472                 maybe_croak(("unknown opt_revision_t string \"%s\": "
473                              "missing closing brace for \"{DATE}\"", input));
474             saved_end = *end;
475             *end = '\0';
476             err = svn_parse_date (&matched, &tm,
477                                   input + 1, apr_time_now(), pool);
478             *end = saved_end;
479             if (err) {
480                 svn_error_clear (err);
481                 maybe_croak(("unknown opt_revision_t string \"%s\": "
482                              "internal svn_parse_date error", input));
483             }
484             if (!matched)
485                 maybe_croak(("unknown opt_revision_t string \"%s\": "
486                              "svn_parse_date failed to parse it", input));
487 
488             rev->kind = svn_opt_revision_date;
489             rev->value.date = tm;
490         } else
491             maybe_croak(("unknown opt_revision_t string \"%s\": must be one of "
492                          "\"BASE\", \"HEAD\", \"WORKING\", \"COMMITTED\", "
493                          "\"PREV\" or a \"{DATE}\"", input));
494     } else
495         maybe_croak(("unknown opt_revision_t type: must be undef, a number, "
496                      "a string (one of \"BASE\", \"HEAD\", \"WORKING\", "
497                      "\"COMMITTED\", \"PREV\" or a \"{DATE}\") "
498                      "or a _p_svn_opt_revision_t object"));
499 
500     return rev;
501 #undef maybe_croak
502 }
503 
504 /* put the va_arg in stack and invoke caller_func with func.
505    fmt:
506    * O: perl object
507    * i: apr_int32_t
508    * u: apr_uint32_t
509    * L: apr_int64_t
510    * U: apr_uint64_t
511    * s: string
512    * S: swigtype
513    * r: svn_revnum_t
514    * b: svn_boolean_t
515    * t: svn_string_t
516    * z: apr_size_t
517 
518    Please do not add C types here.  Add a new format code if needed.
519    Using the underlying C types and not the APR or SVN types can break
520    things if these data types change in the future or on platforms which
521    use different types.
522 
523    put returned value in result if result is not NULL
524 */
525 
526 /* NOTE: calls back into Perl (directly) */
svn_swig_pl_callback_thunk(perl_func_invoker_t caller_func,void * func,SV ** result,const char * fmt,...)527 svn_error_t *svn_swig_pl_callback_thunk(perl_func_invoker_t caller_func,
528                                         void *func,
529                                         SV **result,
530                                         const char *fmt, ...)
531 {
532     const char *fp = fmt;
533     va_list ap;
534     int count;
535     I32 call_flags = result ? G_SCALAR : (G_VOID & G_DISCARD);
536 
537     dSP ;
538     ENTER ;
539     SAVETMPS ;
540 
541     PUSHMARK(SP) ;
542 
543     va_start(ap, fmt);
544     while (*fp) {
545         char *c;
546         void *o;
547         SV *obj;
548         swig_type_info *t;
549         svn_string_t *str;
550 
551         switch (*fp++) {
552         case 'O':
553           XPUSHs(va_arg(ap, SV *));
554             break;
555         case 'S': /* swig object */
556           o = va_arg(ap, void *);
557           t = va_arg(ap, swig_type_info *);
558 
559           obj = sv_newmortal();
560           SWIG_MakePtr(obj, o, t, 0);
561             XPUSHs(obj);
562             break;
563 
564         case 's': /* string */
565           c = va_arg(ap, char *);
566             XPUSHs(c ? sv_2mortal(newSVpv(c, 0)) : &PL_sv_undef);
567             break;
568 
569         case 'i': /* apr_int32_t */
570             XPUSHs(sv_2mortal(newSViv(va_arg(ap, apr_int32_t))));
571             break;
572 
573         case 'u': /* apr_uint32_t */
574             XPUSHs(sv_2mortal(newSViv(va_arg(ap, apr_uint32_t))));
575             break;
576 
577         case 'r': /* svn_revnum_t */
578             XPUSHs(sv_2mortal(newSViv(va_arg(ap, svn_revnum_t))));
579             break;
580 
581         case 'b': /* svn_boolean_t */
582             XPUSHs(sv_2mortal(newSViv(va_arg(ap, svn_boolean_t))));
583             break;
584 
585         case 't': /* svn_string_t */
586             str = va_arg(ap, svn_string_t *);
587             XPUSHs(str ? sv_2mortal(newSVpv(str->data, str->len))
588                    : &PL_sv_undef);
589             break;
590 
591         case 'L': /* apr_int64_t */
592             /* Pass into perl as a string because some implementations may
593              * not be able to handle a 64-bit int.  If it's too long to
594              * fit in Perl's interal IV size then perl will only make
595              * it available as a string.  If not then perl will convert
596              * it to an IV for us.  So this handles the problem gracefully */
597             c = malloc(30);
598             snprintf(c,30,"%" APR_INT64_T_FMT,va_arg(ap, apr_int64_t));
599             XPUSHs(sv_2mortal(newSVpv(c, 0)));
600             free(c);
601             break;
602 
603         case 'U': /* apr_uint64_t */
604             c = malloc(30);
605             snprintf(c,30,"%" APR_UINT64_T_FMT,va_arg(ap, apr_uint64_t));
606             XPUSHs(sv_2mortal(newSVpv(c, 0)));
607             free(c);
608             break;
609 
610         case 'z': /* apr_size_t */
611             if (sizeof(apr_size_t) >= 8)
612               {
613                 c = malloc(30);
614                 snprintf(c,30,"%" APR_SIZE_T_FMT,va_arg(ap, apr_size_t));
615                 XPUSHs(sv_2mortal(newSVpv(c, 0)));
616                 free(c);
617               }
618             else
619               {
620                 XPUSHs(sv_2mortal(newSViv(va_arg(ap, apr_size_t))));
621               }
622              break;
623         }
624     }
625 
626     va_end(ap);
627 
628     PUTBACK;
629     switch (caller_func) {
630     case CALL_SV:
631       count = call_sv(func, call_flags );
632         break;
633     case CALL_METHOD:
634       count = call_method(func, call_flags );
635         break;
636     default:
637       croak("unkonwn calling type");
638         break;
639     }
640     SPAGAIN ;
641 
642     if (((call_flags & G_SCALAR) && count != 1) ||
643         ((call_flags & G_VOID) && count != 0))
644       croak("Wrong number of returns");
645 
646     if (result) {
647         *result = POPs;
648         SvREFCNT_inc(*result);
649     }
650 
651     PUTBACK;
652     FREETMPS ;
653     LEAVE ;
654 
655     return SVN_NO_ERROR;
656 }
657 
658 /*** Editor Wrapping ***/
659 
660 /* this could be more perlish */
661 typedef struct item_baton {
662     SV *editor;     /* the editor handling the callbacks */
663     SV *baton;      /* the dir/file baton (or NULL for edit baton) */
664 } item_baton;
665 
make_baton(apr_pool_t * pool,SV * editor,SV * baton)666 static item_baton * make_baton(apr_pool_t *pool,
667                                SV *editor, SV *baton)
668 {
669     item_baton *newb = apr_palloc(pool, sizeof(*newb));
670 
671     newb->editor = editor;
672     newb->baton = baton;
673 
674     return newb;
675 }
676 
677 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
close_baton(void * baton,const char * method,apr_pool_t * pool)678 static svn_error_t * close_baton(void *baton, const char *method, apr_pool_t *pool)
679 {
680     item_baton *ib = baton;
681 
682     if (ib->baton) {
683       SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
684                                          (void *)method, NULL,
685                                          "OOS", ib->editor, ib->baton,
686                                          pool, POOLINFO));
687         SvREFCNT_dec(ib->baton);
688     }
689     else {
690       SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
691                                          (void *)method, NULL,
692                                          "OS", ib->editor, pool, POOLINFO));
693     }
694 
695     return SVN_NO_ERROR;
696 }
697 
698 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_set_target_revision(void * edit_baton,svn_revnum_t target_revision,apr_pool_t * pool)699 static svn_error_t * thunk_set_target_revision(void *edit_baton,
700                                                svn_revnum_t target_revision,
701                                                apr_pool_t *pool)
702 {
703     item_baton *ib = edit_baton;
704 
705     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
706                                        (void *)"set_target_revision", NULL,
707                                        "Or", ib->editor, target_revision));
708 
709     return SVN_NO_ERROR;
710 }
711 
712 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_open_root(void * edit_baton,svn_revnum_t base_revision,apr_pool_t * dir_pool,void ** root_baton)713 static svn_error_t * thunk_open_root(void *edit_baton,
714                                      svn_revnum_t base_revision,
715                                      apr_pool_t *dir_pool,
716                                      void **root_baton)
717 {
718     item_baton *ib = edit_baton;
719     SV *result;
720 
721     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
722                                        (void *)"open_root", &result,
723                                        "OrS", ib->editor, base_revision,
724                                        dir_pool, POOLINFO));
725 
726     *root_baton = make_baton(dir_pool, ib->editor, result);
727     return SVN_NO_ERROR;
728 }
729 
730 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_delete_entry(const char * path,svn_revnum_t revision,void * parent_baton,apr_pool_t * pool)731 static svn_error_t * thunk_delete_entry(const char *path,
732                                         svn_revnum_t revision,
733                                         void *parent_baton,
734                                         apr_pool_t *pool)
735 {
736     item_baton *ib = parent_baton;
737 
738     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
739                                        (void *)"delete_entry", NULL,
740                                        "OsrOS", ib->editor, path, revision,
741                                        ib->baton, pool, POOLINFO));
742     return SVN_NO_ERROR;
743 }
744 
745 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_add_directory(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * dir_pool,void ** child_baton)746 static svn_error_t * thunk_add_directory(const char *path,
747                                          void *parent_baton,
748                                          const char *copyfrom_path,
749                                          svn_revnum_t copyfrom_revision,
750                                          apr_pool_t *dir_pool,
751                                          void **child_baton)
752 {
753     item_baton *ib = parent_baton;
754     SV *result;
755 
756     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
757                                        (void *)"add_directory", &result,
758                                        "OsOsrS", ib->editor, path, ib->baton,
759                                        copyfrom_path, copyfrom_revision,
760                                        dir_pool, POOLINFO));
761     *child_baton = make_baton(dir_pool, ib->editor, result);
762     return SVN_NO_ERROR;
763 }
764 
765 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_open_directory(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * dir_pool,void ** child_baton)766 static svn_error_t * thunk_open_directory(const char *path,
767                                           void *parent_baton,
768                                           svn_revnum_t base_revision,
769                                           apr_pool_t *dir_pool,
770                                           void **child_baton)
771 {
772     item_baton *ib = parent_baton;
773     SV *result;
774 
775     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
776                                        (void *)"open_directory", &result,
777                                        "OsOrS", ib->editor, path, ib->baton,
778                                        base_revision, dir_pool, POOLINFO));
779 
780     *child_baton = make_baton(dir_pool, ib->editor, result);
781 
782     return SVN_NO_ERROR;
783 }
784 
785 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_change_dir_prop(void * dir_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)786 static svn_error_t * thunk_change_dir_prop(void *dir_baton,
787                                            const char *name,
788                                            const svn_string_t *value,
789                                            apr_pool_t *pool)
790 {
791     item_baton *ib = dir_baton;
792 
793     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
794                                        (void *)"change_dir_prop", NULL,
795                                        "OOstS", ib->editor, ib->baton, name,
796                                        value, pool, POOLINFO));
797 
798     return SVN_NO_ERROR;
799 }
800 
801 /* NOTE: calls back into Perl (by calling close_baton) */
thunk_close_directory(void * dir_baton,apr_pool_t * pool)802 static svn_error_t * thunk_close_directory(void *dir_baton,
803                                            apr_pool_t *pool)
804 {
805     return close_baton(dir_baton, "close_directory", pool);
806 }
807 
808 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_absent_directory(const char * path,void * parent_baton,apr_pool_t * pool)809 static svn_error_t * thunk_absent_directory(const char *path,
810                                             void *parent_baton,
811                                             apr_pool_t *pool)
812 {
813     item_baton *ib = parent_baton;
814 
815     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
816                                        (void *)"absent_directory", NULL,
817                                        "OsOS", ib->editor, path, ib->baton,
818                                        pool, POOLINFO));
819 
820     return SVN_NO_ERROR;
821 }
822 
823 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_add_file(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * file_pool,void ** file_baton)824 static svn_error_t * thunk_add_file(const char *path,
825                                     void *parent_baton,
826                                     const char *copyfrom_path,
827                                     svn_revnum_t copyfrom_revision,
828                                     apr_pool_t *file_pool,
829                                     void **file_baton)
830 {
831     item_baton *ib = parent_baton;
832     SV *result;
833 
834     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
835                                        (void *)"add_file", &result,
836                                        "OsOsrS", ib->editor, path, ib->baton,
837                                        copyfrom_path, copyfrom_revision,
838                                        file_pool, POOLINFO));
839 
840     *file_baton = make_baton(file_pool, ib->editor, result);
841     return SVN_NO_ERROR;
842 }
843 
844 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_open_file(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * file_pool,void ** file_baton)845 static svn_error_t * thunk_open_file(const char *path,
846                                      void *parent_baton,
847                                      svn_revnum_t base_revision,
848                                      apr_pool_t *file_pool,
849                                      void **file_baton)
850 {
851     item_baton *ib = parent_baton;
852     SV *result;
853 
854     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
855                                        (void *)"open_file", &result,
856                                        "OsOrS", ib->editor, path, ib->baton,
857                                        base_revision, file_pool, POOLINFO));
858 
859     *file_baton = make_baton(file_pool, ib->editor, result);
860     return SVN_NO_ERROR;
861 }
862 
863 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_window_handler(svn_txdelta_window_t * window,void * baton)864 static svn_error_t * thunk_window_handler(svn_txdelta_window_t *window,
865                                           void *baton)
866 {
867     SV *handler = baton;
868 
869     if (window == NULL) {
870       SVN_ERR(svn_swig_pl_callback_thunk(CALL_SV,
871                                          handler, NULL, "O",
872                                          &PL_sv_undef));
873         SvREFCNT_dec(handler);
874     }
875     else {
876         swig_type_info *tinfo = _SWIG_TYPE("svn_txdelta_window_t *");
877         SVN_ERR(svn_swig_pl_callback_thunk(CALL_SV, handler,
878                                            NULL, "S", window, tinfo));
879     }
880 
881     return SVN_NO_ERROR;
882 }
883 
884 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
885 static svn_error_t *
thunk_apply_textdelta(void * file_baton,const char * base_checksum,apr_pool_t * pool,svn_txdelta_window_handler_t * handler,void ** h_baton)886 thunk_apply_textdelta(void *file_baton,
887                       const char *base_checksum,
888                       apr_pool_t *pool,
889                       svn_txdelta_window_handler_t *handler,
890                       void **h_baton)
891 {
892     item_baton *ib = file_baton;
893     SV *result;
894 
895     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
896                                        (void *)"apply_textdelta", &result,
897                                        "OOsS", ib->editor, ib->baton,
898                                        base_checksum, pool, POOLINFO));
899     if (SvOK(result)) {
900         if (SvROK(result) && SvTYPE(SvRV(result)) == SVt_PVAV) {
901             swig_type_info *handler_info =
902               _SWIG_TYPE("svn_txdelta_window_handler_t");
903             swig_type_info *void_info = _SWIG_TYPE("void *");
904             AV *array = (AV *)SvRV(result);
905 
906             if (SWIG_ConvertPtr(*av_fetch(array, 0, 0),
907                                 (void **)handler, handler_info,0) < 0) {
908                 croak("Unable to convert from SWIG Type");
909             }
910             if (SWIG_ConvertPtr(*av_fetch(array, 1, 0),
911                                 h_baton, void_info,0) < 0) {
912                 croak("Unable to convert from SWIG Type ");
913             }
914             SvREFCNT_dec(result);
915         }
916         else {
917             *handler = thunk_window_handler;
918             *h_baton = result;
919         }
920     }
921     else {
922         *handler = svn_delta_noop_window_handler;
923         *h_baton = NULL;
924     }
925 
926     return SVN_NO_ERROR;
927 }
928 
929 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_change_file_prop(void * file_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)930 static svn_error_t * thunk_change_file_prop(void *file_baton,
931                                             const char *name,
932                                             const svn_string_t *value,
933                                             apr_pool_t *pool)
934 {
935     item_baton *ib = file_baton;
936 
937     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
938                                        (void *)"change_file_prop", NULL,
939                                        "OOstS", ib->editor, ib->baton, name,
940                                        value, pool, POOLINFO));
941 
942     return SVN_NO_ERROR;
943 }
944 
945 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_close_file(void * file_baton,const char * text_checksum,apr_pool_t * pool)946 static svn_error_t * thunk_close_file(void *file_baton,
947                                       const char *text_checksum,
948                                       apr_pool_t *pool)
949 {
950     item_baton *ib = file_baton;
951 
952     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
953                                        (void *)"close_file", NULL, "OOsS",
954                                        ib->editor, ib->baton, text_checksum,
955                                        pool, POOLINFO));
956 
957     SvREFCNT_dec(ib->baton);
958 
959     return SVN_NO_ERROR;
960 }
961 
962 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_absent_file(const char * path,void * parent_baton,apr_pool_t * pool)963 static svn_error_t * thunk_absent_file(const char *path,
964                                        void *parent_baton,
965                                        apr_pool_t *pool)
966 {
967     item_baton *ib = parent_baton;
968 
969     SVN_ERR(svn_swig_pl_callback_thunk(CALL_METHOD,
970                                        (void *)"absent_file", NULL,
971                                        "OsOS", ib->editor, path, ib->baton,
972                                        pool, POOLINFO));
973 
974     return SVN_NO_ERROR;
975 }
976 
977 /* NOTE: calls back into Perl (by calling close_baton) */
thunk_close_edit(void * edit_baton,apr_pool_t * pool)978 static svn_error_t * thunk_close_edit(void *edit_baton,
979                                       apr_pool_t *pool)
980 {
981     return close_baton(edit_baton, "close_edit", pool);
982 }
983 
984 /* NOTE: calls back into Perl (by calling close_baton) */
thunk_abort_edit(void * edit_baton,apr_pool_t * pool)985 static svn_error_t * thunk_abort_edit(void *edit_baton,
986                                       apr_pool_t *pool)
987 {
988     return close_baton(edit_baton, "abort_edit", pool);
989 }
990 
991 
svn_swig_pl_make_editor(svn_delta_editor_t ** editor,void ** edit_baton,SV * perl_editor,apr_pool_t * pool)992 void svn_swig_pl_make_editor(svn_delta_editor_t **editor,
993                              void **edit_baton,
994                              SV *perl_editor,
995                              apr_pool_t *pool)
996 {
997   svn_delta_editor_t *thunk_editor = svn_delta_default_editor(pool);
998 
999     thunk_editor->set_target_revision = thunk_set_target_revision;
1000     thunk_editor->open_root = thunk_open_root;
1001     thunk_editor->delete_entry = thunk_delete_entry;
1002     thunk_editor->add_directory = thunk_add_directory;
1003     thunk_editor->open_directory = thunk_open_directory;
1004     thunk_editor->change_dir_prop = thunk_change_dir_prop;
1005     thunk_editor->close_directory = thunk_close_directory;
1006     thunk_editor->absent_directory = thunk_absent_directory;
1007     thunk_editor->add_file = thunk_add_file;
1008     thunk_editor->open_file = thunk_open_file;
1009     thunk_editor->apply_textdelta = thunk_apply_textdelta;
1010     thunk_editor->change_file_prop = thunk_change_file_prop;
1011     thunk_editor->close_file = thunk_close_file;
1012     thunk_editor->absent_file = thunk_absent_file;
1013     thunk_editor->close_edit = thunk_close_edit;
1014     thunk_editor->abort_edit = thunk_abort_edit;
1015 
1016     *editor = thunk_editor;
1017     *edit_baton = make_baton(pool, perl_editor, NULL);
1018     svn_swig_pl_hold_ref_in_pool(pool, perl_editor);
1019 }
1020 
1021 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_log_receiver(void * baton,apr_hash_t * changed_paths,svn_revnum_t rev,const char * author,const char * date,const char * msg,apr_pool_t * pool)1022 svn_error_t *svn_swig_pl_thunk_log_receiver(void *baton,
1023                                             apr_hash_t *changed_paths,
1024                                             svn_revnum_t rev,
1025                                             const char *author,
1026                                             const char *date,
1027                                             const char *msg,
1028                                             apr_pool_t *pool)
1029 {
1030     SV *receiver = baton;
1031     swig_type_info *tinfo = _SWIG_TYPE("svn_log_changed_path_t *");
1032 
1033     if (!SvOK(receiver))
1034         return SVN_NO_ERROR;
1035 
1036     svn_swig_pl_callback_thunk(CALL_SV,
1037                                receiver, NULL,
1038                                "OrsssS", (changed_paths) ?
1039                                svn_swig_pl_convert_hash(changed_paths, tinfo)
1040                                : &PL_sv_undef,
1041                                rev, author, date, msg, pool, POOLINFO);
1042 
1043     return SVN_NO_ERROR;
1044 }
1045 
1046 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_log_entry_receiver(void * baton,svn_log_entry_t * log_entry,apr_pool_t * pool)1047 svn_error_t *svn_swig_pl_thunk_log_entry_receiver(void *baton,
1048                                                   svn_log_entry_t *log_entry,
1049                                                   apr_pool_t *pool)
1050 {
1051     SV *receiver = baton;
1052 
1053     if (!SvOK(receiver))
1054         return SVN_NO_ERROR;
1055 
1056     svn_swig_pl_callback_thunk(CALL_SV,
1057                                receiver, NULL,
1058                                "SS",
1059                                log_entry, _SWIG_TYPE("svn_log_entry_t *"),
1060                                pool, POOLINFO);
1061 
1062     return SVN_NO_ERROR;
1063 }
1064 
1065 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_client_diff_summarize_func(const svn_client_diff_summarize_t * diff,void * baton,apr_pool_t * pool)1066 svn_error_t * svn_swig_pl_thunk_client_diff_summarize_func(
1067                      const svn_client_diff_summarize_t *diff,
1068                      void *baton,
1069                      apr_pool_t *pool)
1070 {
1071     SV *func = baton;
1072 
1073     if(!SvOK(func))
1074     return SVN_NO_ERROR;
1075 
1076     svn_swig_pl_callback_thunk(CALL_SV,
1077                                func, NULL,
1078                                "SS", diff,
1079                                _SWIG_TYPE("svn_client_diff_summarize_t *"),
1080                                pool, POOLINFO);
1081 
1082     return SVN_NO_ERROR;
1083 }
1084 
1085 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_history_func(void * baton,const char * path,svn_revnum_t revision,apr_pool_t * pool)1086 svn_error_t *svn_swig_pl_thunk_history_func(void *baton,
1087                                             const char *path,
1088                                             svn_revnum_t revision,
1089                                             apr_pool_t *pool)
1090 {
1091     SV *func = baton;
1092 
1093     if (!SvOK(func))
1094         return SVN_NO_ERROR;
1095 
1096     svn_swig_pl_callback_thunk(CALL_SV,
1097                                func, NULL,
1098                                "srS", path, revision, pool, POOLINFO);
1099 
1100     return SVN_NO_ERROR;
1101 }
1102 
1103 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_authz_func(svn_boolean_t * allowed,svn_fs_root_t * root,const char * path,void * baton,apr_pool_t * pool)1104 svn_error_t *svn_swig_pl_thunk_authz_func(svn_boolean_t *allowed,
1105                                           svn_fs_root_t *root,
1106                                           const char *path,
1107                                           void *baton,
1108                                           apr_pool_t *pool)
1109 {
1110     SV *func = baton, *result;
1111 
1112     if (!SvOK(func))
1113         return SVN_NO_ERROR;
1114 
1115     svn_swig_pl_callback_thunk(CALL_SV,
1116                                func, &result,
1117                                "SsS", root, _SWIG_TYPE("svn_fs_root_t *"),
1118                                path, pool, POOLINFO);
1119 
1120     *allowed = SvIV(result);
1121     SvREFCNT_dec(result);
1122 
1123     return SVN_NO_ERROR;
1124 }
1125 
1126 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_commit_callback(svn_revnum_t new_revision,const char * date,const char * author,void * baton)1127 svn_error_t *svn_swig_pl_thunk_commit_callback(svn_revnum_t new_revision,
1128                                                const char *date,
1129                                                const char *author,
1130                                                void *baton)
1131 {
1132     if (!SvOK((SV *)baton))
1133         return SVN_NO_ERROR;
1134 
1135     svn_swig_pl_callback_thunk(CALL_SV, baton, NULL,
1136                                "rss", new_revision, date, author);
1137 
1138     return SVN_NO_ERROR;
1139 }
1140 
1141 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_commit_callback2(const svn_commit_info_t * commit_info,void * baton,apr_pool_t * pool)1142 svn_error_t *svn_swig_pl_thunk_commit_callback2(const svn_commit_info_t *commit_info,
1143                                                 void *baton,
1144                                                 apr_pool_t *pool)
1145 {
1146     if (!SvOK((SV *)baton))
1147         return SVN_NO_ERROR;
1148 
1149     svn_swig_pl_callback_thunk(CALL_SV, baton, NULL,
1150                                "SS",
1151                                commit_info, _SWIG_TYPE("svn_commit_info_t *"),
1152                                pool, POOLINFO);
1153 
1154     return SVN_NO_ERROR;
1155 }
1156 
1157 
1158 /* Wrap RA */
1159 
1160 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_open_tmp_file(apr_file_t ** fp,void * callback_baton,apr_pool_t * pool)1161 static svn_error_t * thunk_open_tmp_file(apr_file_t **fp,
1162                                          void *callback_baton,
1163                                          apr_pool_t *pool)
1164 {
1165     SV *result;
1166     swig_type_info *tinfo = _SWIG_TYPE("apr_file_t *");
1167 
1168     svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"open_tmp_file",
1169                                &result, "OS", callback_baton, pool, POOLINFO);
1170 
1171     if (SWIG_ConvertPtr(result, (void *)fp, tinfo,0) < 0) {
1172         croak("Unable to convert from SWIG Type");
1173     }
1174 
1175     SvREFCNT_dec(result);
1176     return SVN_NO_ERROR;
1177 }
1178 
1179 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
thunk_get_wc_prop(void * baton,const char * relpath,const char * name,const svn_string_t ** value,apr_pool_t * pool)1180 static svn_error_t *thunk_get_wc_prop(void *baton,
1181                                       const char *relpath,
1182                                       const char *name,
1183                                       const svn_string_t **value,
1184                                       apr_pool_t *pool)
1185 {
1186     SV *result;
1187     char *data;
1188     STRLEN len;
1189 
1190     svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"get_wc_prop",
1191                                &result, "OssS", baton, relpath, name,
1192                                pool, POOLINFO);
1193 
1194     /* this is svn_string_t * typemap in */
1195     if (!SvOK(result) || result == &PL_sv_undef) {
1196         *value = NULL;
1197     }
1198     else if (SvPOK(result)) {
1199         data = SvPV(result, len);
1200         *value = svn_string_ncreate(data, len, pool);
1201     }
1202     else {
1203         SvREFCNT_dec(result);
1204         croak("not a string");
1205     }
1206 
1207     SvREFCNT_dec(result);
1208     return SVN_NO_ERROR;
1209 }
1210 
1211 
svn_swig_pl_make_callbacks(svn_ra_callbacks_t ** cb,void ** c_baton,SV * perl_callbacks,apr_pool_t * pool)1212 svn_error_t *svn_swig_pl_make_callbacks(svn_ra_callbacks_t **cb,
1213                                         void **c_baton,
1214                                         SV *perl_callbacks,
1215                                         apr_pool_t *pool)
1216 {
1217     SV *auth_baton;
1218 
1219     *cb = apr_pcalloc(pool, sizeof(**cb));
1220 
1221     (*cb)->open_tmp_file = thunk_open_tmp_file;
1222     (*cb)->get_wc_prop = thunk_get_wc_prop;
1223     (*cb)->set_wc_prop = NULL;
1224     (*cb)->push_wc_prop = NULL;
1225     (*cb)->invalidate_wc_props = NULL;
1226     auth_baton = *hv_fetch((HV *)SvRV(perl_callbacks), "auth", 4, 0);
1227 
1228     if (SWIG_ConvertPtr(auth_baton,
1229                         (void **)&(*cb)->auth_baton, _SWIG_TYPE("svn_auth_baton_t *"),0) < 0) {
1230         croak("Unable to convert from SWIG Type");
1231     }
1232     *c_baton = perl_callbacks;
1233     svn_swig_pl_hold_ref_in_pool(pool, perl_callbacks);
1234     return SVN_NO_ERROR;
1235 }
1236 
1237 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char ** keyring_password,const char * keyring_name,void * baton,apr_pool_t * pool)1238 svn_error_t *svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char **keyring_password,
1239                                                            const char *keyring_name,
1240                                                            void *baton,
1241                                                            apr_pool_t *pool)
1242 {
1243     SV *result;
1244     STRLEN len;
1245     /* The baton is the actual prompt function passed from perl, so we
1246      * call that one and process the result. */
1247     svn_swig_pl_callback_thunk(CALL_SV,
1248                                baton, &result,
1249                                "sS", keyring_name,
1250                                pool, POOLINFO);
1251     if (!SvOK(result) || result == &PL_sv_undef) {
1252         *keyring_password = NULL;
1253     }
1254     else if (SvPOK(result)) {
1255         *keyring_password = apr_pstrdup(pool, SvPV(result, len));
1256     }
1257     else {
1258         SvREFCNT_dec(result);
1259         croak("not a string");
1260     }
1261 
1262     SvREFCNT_dec(result);
1263     return SVN_NO_ERROR;
1264 }
1265 
1266 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t ** cred,void * baton,const char * realm,const char * username,svn_boolean_t may_save,apr_pool_t * pool)1267 svn_error_t *svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t **cred,
1268                                              void *baton,
1269                                              const char *realm,
1270                                              const char *username,
1271                                              svn_boolean_t may_save,
1272                                              apr_pool_t *pool)
1273 {
1274     /* Be nice and allocate the memory for the cred structure before passing it
1275      * off to the perl space */
1276   *cred = apr_pcalloc(pool, sizeof(**cred));
1277     if (!*cred) {
1278       croak("Could not allocate memory for cred structure");
1279     }
1280     svn_swig_pl_callback_thunk(CALL_SV,
1281                                baton, NULL,
1282                                "SssbS", *cred, _SWIG_TYPE("svn_auth_cred_simple_t *"),
1283                                realm, username, may_save, pool, POOLINFO);
1284 
1285     return SVN_NO_ERROR;
1286 }
1287 
1288 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_username_prompt(svn_auth_cred_username_t ** cred,void * baton,const char * realm,svn_boolean_t may_save,apr_pool_t * pool)1289 svn_error_t *svn_swig_pl_thunk_username_prompt(svn_auth_cred_username_t **cred,
1290                                                void *baton,
1291                                                const char *realm,
1292                                                svn_boolean_t may_save,
1293                                                apr_pool_t *pool)
1294 {
1295     /* Be nice and allocate the memory for the cred structure before passing it
1296      * off to the perl space */
1297   *cred = apr_pcalloc(pool, sizeof(**cred));
1298     if (!*cred) {
1299       croak("Could not allocate memory for cred structure");
1300     }
1301     svn_swig_pl_callback_thunk(CALL_SV,
1302                                baton, NULL,
1303                                "SsbS", *cred, _SWIG_TYPE("svn_auth_cred_username_t *"),
1304                                realm, may_save, pool, POOLINFO);
1305 
1306     return SVN_NO_ERROR;
1307 }
1308 
1309 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_ssl_server_trust_prompt(svn_auth_cred_ssl_server_trust_t ** cred,void * baton,const char * realm,apr_uint32_t failures,const svn_auth_ssl_server_cert_info_t * cert_info,svn_boolean_t may_save,apr_pool_t * pool)1310 svn_error_t *svn_swig_pl_thunk_ssl_server_trust_prompt(
1311                               svn_auth_cred_ssl_server_trust_t **cred,
1312                               void *baton,
1313                               const char *realm,
1314                               apr_uint32_t failures,
1315                               const svn_auth_ssl_server_cert_info_t *cert_info,
1316                               svn_boolean_t may_save,
1317                               apr_pool_t *pool)
1318 {
1319     /* Be nice and allocate the memory for the cred structure before passing it
1320      * off to the perl space */
1321   *cred = apr_pcalloc(pool, sizeof(**cred));
1322     if (!*cred) {
1323       croak("Could not allocate memory for cred structure");
1324     }
1325     svn_swig_pl_callback_thunk(CALL_SV,
1326                                baton, NULL,
1327                                "SsiSbS", *cred, _SWIG_TYPE("svn_auth_cred_ssl_server_trust_t *"),
1328                                realm, failures,
1329                                cert_info, _SWIG_TYPE("svn_auth_ssl_server_cert_info_t *"),
1330                                may_save, pool, POOLINFO);
1331 
1332     /* Allow the perl callback to indicate failure by setting all vars to 0
1333      * or by simply doing nothing.  While still allowing them to indicate
1334      * failure by setting the cred strucutre's pointer to 0 via $$cred = 0 */
1335     if (*cred) {
1336         if ((*cred)->may_save == 0 && (*cred)->accepted_failures == 0) {
1337             *cred = NULL;
1338         }
1339     }
1340 
1341     return SVN_NO_ERROR;
1342 }
1343 
1344 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_ssl_client_cert_prompt(svn_auth_cred_ssl_client_cert_t ** cred,void * baton,const char * realm,svn_boolean_t may_save,apr_pool_t * pool)1345 svn_error_t *svn_swig_pl_thunk_ssl_client_cert_prompt(
1346                 svn_auth_cred_ssl_client_cert_t **cred,
1347                 void *baton,
1348                 const char * realm,
1349                 svn_boolean_t may_save,
1350                 apr_pool_t *pool)
1351 {
1352     /* Be nice and allocate the memory for the cred structure before passing it
1353      * off to the perl space */
1354   *cred = apr_pcalloc(pool, sizeof(**cred));
1355     if (!*cred) {
1356       croak("Could not allocate memory for cred structure");
1357     }
1358     svn_swig_pl_callback_thunk(CALL_SV,
1359                                baton, NULL,
1360                                "SsbS", *cred, _SWIG_TYPE("svn_auth_cred_ssl_client_cert_t *"),
1361                                realm, may_save, pool, POOLINFO);
1362 
1363     return SVN_NO_ERROR;
1364 }
1365 
1366 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_ssl_client_cert_pw_prompt(svn_auth_cred_ssl_client_cert_pw_t ** cred,void * baton,const char * realm,svn_boolean_t may_save,apr_pool_t * pool)1367 svn_error_t *svn_swig_pl_thunk_ssl_client_cert_pw_prompt(
1368                                      svn_auth_cred_ssl_client_cert_pw_t **cred,
1369                                      void *baton,
1370                                      const char *realm,
1371                                      svn_boolean_t may_save,
1372                                      apr_pool_t *pool)
1373 {
1374     /* Be nice and allocate the memory for the cred structure before passing it
1375      * off to the perl space */
1376   *cred = apr_pcalloc(pool, sizeof(**cred));
1377     if (!*cred) {
1378       croak("Could not allocate memory for cred structure");
1379     }
1380     svn_swig_pl_callback_thunk(CALL_SV,
1381                                baton, NULL,
1382                                "SsbS", *cred, _SWIG_TYPE("svn_auth_cred_ssl_client_cert_pw_t *"),
1383                                realm, may_save, pool, POOLINFO);
1384 
1385     return SVN_NO_ERROR;
1386 }
1387 
1388 /* Thunked version of svn_wc_notify_func_t callback type */
1389 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_notify_func(void * baton,const char * path,svn_wc_notify_action_t action,svn_node_kind_t kind,const char * mime_type,svn_wc_notify_state_t content_state,svn_wc_notify_state_t prop_state,svn_revnum_t revision)1390 void svn_swig_pl_notify_func(void * baton,
1391                              const char *path,
1392                              svn_wc_notify_action_t action,
1393                              svn_node_kind_t kind,
1394                              const char *mime_type,
1395                              svn_wc_notify_state_t content_state,
1396                              svn_wc_notify_state_t prop_state,
1397                              svn_revnum_t revision)
1398 {
1399     if (!SvOK((SV *)baton)) {
1400         return;
1401     }
1402 
1403     svn_swig_pl_callback_thunk(CALL_SV,
1404                                baton, NULL,
1405                                "siisiir", path, action, kind, mime_type,
1406                                content_state, prop_state, revision);
1407 
1408 }
1409 
1410 /* Thunked version of svn_client_get_commit_log3_t callback type. */
1411 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_get_commit_log_func(const char ** log_msg,const char ** tmp_file,const apr_array_header_t * commit_items,void * baton,apr_pool_t * pool)1412 svn_error_t *svn_swig_pl_get_commit_log_func(const char **log_msg,
1413                                              const char **tmp_file,
1414                                              const apr_array_header_t *
1415                                              commit_items,
1416                                              void *baton,
1417                                              apr_pool_t *pool)
1418 {
1419     SV *result;
1420     svn_error_t *ret_val = SVN_NO_ERROR;
1421     SV *log_msg_sv;
1422     SV *tmp_file_sv;
1423     SV *commit_items_sv;
1424 
1425     if (!SvOK((SV *)baton)) {
1426       *log_msg = apr_pstrdup(pool, "");
1427         *tmp_file = NULL;
1428         return SVN_NO_ERROR;
1429     }
1430 
1431     log_msg_sv = newRV_noinc(sv_newmortal());
1432     tmp_file_sv = newRV_noinc(sv_newmortal());
1433     commit_items_sv = svn_swig_pl_convert_array
1434       (commit_items, _SWIG_TYPE("svn_client_commit_item3_t *"));
1435 
1436     svn_swig_pl_callback_thunk(CALL_SV,
1437                                baton, &result,
1438                                "OOOS", log_msg_sv, tmp_file_sv,
1439                                commit_items_sv, pool, POOLINFO);
1440 
1441     if (!SvOK(SvRV(log_msg_sv))) {
1442         /* client returned undef to us */
1443         *log_msg = NULL;
1444     } else if (SvPOK(SvRV(log_msg_sv))) {
1445         /* client returned string so get the string and then duplicate
1446          * it using pool memory */
1447         *log_msg = apr_pstrdup(pool, SvPV_nolen(SvRV(log_msg_sv)));
1448     } else {
1449         croak("Invalid value in log_msg reference, must be undef or a string");
1450     }
1451 
1452     if (!SvOK(SvRV(tmp_file_sv))) {
1453         *tmp_file = NULL;
1454     } else if (SvPOK(SvRV(tmp_file_sv))) {
1455         *tmp_file = apr_pstrdup(pool, SvPV_nolen(SvRV(tmp_file_sv)));
1456     } else {
1457         croak("Invalid value in tmp_file reference, "
1458               "must be undef or a string");
1459     }
1460 
1461     if (sv_derived_from(result, "_p_svn_error_t")) {
1462         swig_type_info *errorinfo = _SWIG_TYPE("svn_error_t *");
1463         if (SWIG_ConvertPtr(result, (void *)&ret_val, errorinfo, 0) < 0) {
1464             SvREFCNT_dec(result);
1465             croak("Unable to convert from SWIG Type");
1466         }
1467     }
1468 
1469     SvREFCNT_dec(result);
1470     return ret_val;
1471 }
1472 
1473 /* Thunked version of svn_client_info_t callback type. */
1474 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_info_receiver(void * baton,const char * path,const svn_info_t * info,apr_pool_t * pool)1475 svn_error_t *svn_swig_pl_info_receiver(void *baton,
1476                                        const char *path,
1477                                        const svn_info_t *info,
1478                                        apr_pool_t *pool)
1479 {
1480     SV *result;
1481     svn_error_t *ret_val;
1482     swig_type_info *infoinfo = _SWIG_TYPE("svn_info_t *");
1483 
1484     if (!SvOK((SV *)baton))
1485         return SVN_NO_ERROR;
1486 
1487     svn_swig_pl_callback_thunk(CALL_SV, baton, &result, "sSS", path, info,
1488                                infoinfo, pool, POOLINFO);
1489 
1490     if (sv_derived_from(result, "_p_svn_error_t")) {
1491         swig_type_info *errorinfo = _SWIG_TYPE("svn_error_t *");
1492         if (SWIG_ConvertPtr(result, (void *)&ret_val, errorinfo, 0) < 0) {
1493             SvREFCNT_dec(result);
1494             croak("Unable to convert from SWIG Type");
1495         }
1496     }
1497     else
1498         ret_val = SVN_NO_ERROR;
1499 
1500     SvREFCNT_dec(result);
1501     return ret_val;
1502 }
1503 
1504 
1505 /* Thunked version of svn_wc_cancel_func_t callback type. */
1506 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_cancel_func(void * cancel_baton)1507 svn_error_t *svn_swig_pl_cancel_func(void *cancel_baton) {
1508     SV *result;
1509     svn_error_t *ret_val;
1510 
1511     if (!SvOK((SV *)cancel_baton)) {
1512         return SVN_NO_ERROR;
1513     }
1514     svn_swig_pl_callback_thunk(CALL_SV, cancel_baton, &result, "");
1515 
1516     if (sv_derived_from(result,"_p_svn_error_t")) {
1517         swig_type_info *errorinfo = _SWIG_TYPE("svn_error_t *");
1518         if (SWIG_ConvertPtr(result, (void *)&ret_val, errorinfo, 0) < 0) {
1519             SvREFCNT_dec(result);
1520             croak("Unable to convert from SWIG Type");
1521         }
1522     } else if (SvIOK(result) && SvIV(result)) {
1523         ret_val = svn_error_create(SVN_ERR_CANCELLED, NULL,
1524                                    "By cancel callback");
1525     } else if (SvTRUE(result) && SvPOK(result)) {
1526         ret_val = svn_error_create(SVN_ERR_CANCELLED, NULL,
1527                                    SvPV_nolen(result));
1528     } else {
1529         ret_val = SVN_NO_ERROR;
1530     }
1531     SvREFCNT_dec(result);
1532     return ret_val;
1533 }
1534 
1535 /* Thunked version of svn_wc_status_func_t callback type. */
1536 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_status_func(void * baton,const char * path,svn_wc_status_t * status)1537 void svn_swig_pl_status_func(void *baton,
1538                              const char *path,
1539                              svn_wc_status_t *status)
1540 {
1541   swig_type_info *statusinfo = _SWIG_TYPE("svn_wc_status_t *");
1542 
1543   if (!SvOK((SV *)baton)) {
1544     return;
1545   }
1546 
1547   svn_swig_pl_callback_thunk(CALL_SV, baton, NULL, "sS",
1548                              path, status, statusinfo);
1549 
1550 }
1551 
1552 /* Thunked version of svn_wc_status_func2_t callback type. */
1553 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_status_func2(void * baton,const char * path,svn_wc_status2_t * status)1554 void svn_swig_pl_status_func2(void *baton,
1555                               const char *path,
1556                               svn_wc_status2_t *status)
1557 {
1558   swig_type_info *statusinfo = _SWIG_TYPE("svn_wc_status2 _t *");
1559 
1560   if (!SvOK((SV *)baton)) {
1561     return;
1562   }
1563 
1564   svn_swig_pl_callback_thunk(CALL_SV, baton, NULL, "sS",
1565                              path, status, statusinfo);
1566 
1567 }
1568 
1569 /* Thunked version of svn_wc_status_func3_t callback type. */
1570 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_status_func3(void * baton,const char * path,svn_wc_status2_t * status,apr_pool_t * pool)1571 svn_error_t *svn_swig_pl_status_func3(void *baton,
1572                                       const char *path,
1573                                       svn_wc_status2_t *status,
1574                                       apr_pool_t *pool)
1575 {
1576   SV *result;
1577   svn_error_t *ret_val = SVN_NO_ERROR;
1578 
1579   swig_type_info *statusinfo = _SWIG_TYPE("svn_wc_status2 _t *");
1580 
1581   if (!SvOK((SV *)baton)) {
1582     return ret_val;
1583   }
1584 
1585   svn_swig_pl_callback_thunk(CALL_SV, baton, &result, "sSS",
1586                              path, status, statusinfo,
1587                              pool, POOLINFO);
1588 
1589   if (sv_derived_from(result, "_p_svn_error_t")) {
1590     swig_type_info *errorinfo = _SWIG_TYPE("svn_error_t *");
1591     if (SWIG_ConvertPtr(result, (void *)&ret_val, errorinfo, 0) < 0) {
1592         SvREFCNT_dec(result);
1593         croak("Unable to convert from SWIG Type");
1594     }
1595   }
1596 
1597   SvREFCNT_dec(result);
1598   return ret_val;
1599 }
1600 
1601 
1602 /* Thunked version of svn_client_blame_receiver_t callback type. */
1603 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_blame_func(void * baton,apr_int64_t line_no,svn_revnum_t revision,const char * author,const char * date,const char * line,apr_pool_t * pool)1604 svn_error_t *svn_swig_pl_blame_func(void *baton,
1605                                     apr_int64_t line_no,
1606                                     svn_revnum_t revision,
1607                                     const char *author,
1608                                     const char *date,
1609                                     const char *line,
1610                                     apr_pool_t *pool)
1611 {
1612     SV *result;
1613     svn_error_t *ret_val = SVN_NO_ERROR;
1614 
1615     svn_swig_pl_callback_thunk(CALL_SV, baton, &result, "LrsssS",
1616                                line_no, revision, author, date, line,
1617                                pool, POOLINFO);
1618 
1619     if (sv_derived_from(result, "_p_svn_error_t")) {
1620         swig_type_info *errorinfo = _SWIG_TYPE("svn_error_t *");
1621         if (SWIG_ConvertPtr(result, (void *)&ret_val, errorinfo, 0) < 0) {
1622             SvREFCNT_dec(result);
1623             croak("Unable to convert from SWIG Type");
1624         }
1625     }
1626 
1627     SvREFCNT_dec(result);
1628     return ret_val;
1629 }
1630 
1631 /* Thunked config enumerator */
1632 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_thunk_config_enumerator(const char * name,const char * value,void * baton)1633 svn_boolean_t svn_swig_pl_thunk_config_enumerator(const char *name, const char *value, void *baton)
1634 {
1635     SV *result;
1636     if (!SvOK((SV *)baton))
1637         return 0;
1638 
1639     svn_swig_pl_callback_thunk(CALL_SV, baton, &result,
1640                                "ss", name, value);
1641 
1642     return SvOK(result);
1643 }
1644 
1645 
1646 /* default pool support */
1647 
1648 static svn_swig_pl_get_current_pool_func_t get_current_pool_cb = NULL;
1649 static svn_swig_pl_set_current_pool_func_t set_current_pool_cb = NULL;
1650 
1651 void
svn_swig_pl__bind_current_pool_fns(svn_swig_pl_get_current_pool_func_t get,svn_swig_pl_set_current_pool_func_t set)1652 svn_swig_pl__bind_current_pool_fns(svn_swig_pl_get_current_pool_func_t get,
1653                                    svn_swig_pl_set_current_pool_func_t set)
1654 {
1655   /* This function should only be called ONCE, otherwise there are two
1656      global variables CURRENT_POOL */
1657   SVN_ERR_ASSERT_NO_RETURN(get_current_pool_cb == NULL
1658                            && set_current_pool_cb == NULL);
1659 
1660   get_current_pool_cb = get;
1661   set_current_pool_cb = set;
1662 }
1663 
svn_swig_pl_get_current_pool()1664 apr_pool_t * svn_swig_pl_get_current_pool()
1665 {
1666   SVN_ERR_ASSERT_NO_RETURN(get_current_pool_cb != NULL);
1667   return get_current_pool_cb();
1668 }
1669 
svn_swig_pl_set_current_pool(apr_pool_t * pool)1670 void svn_swig_pl_set_current_pool(apr_pool_t *pool)
1671 {
1672   SVN_ERR_ASSERT_NO_RETURN(set_current_pool_cb != NULL);
1673   set_current_pool_cb(pool);
1674 }
1675 
1676 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_make_pool(SV * obj)1677 apr_pool_t *svn_swig_pl_make_pool(SV *obj)
1678 {
1679     apr_pool_t *pool;
1680 
1681     if (obj && sv_isobject(obj)) {
1682       if (sv_derived_from(obj, "SVN::Pool")) {
1683             obj = SvRV(obj);
1684         }
1685         if (sv_derived_from(obj, "_p_apr_pool_t")) {
1686             SWIG_ConvertPtr(obj, (void **)&pool, POOLINFO, 0);
1687             return pool;
1688         }
1689     }
1690 
1691     if (!svn_swig_pl_get_current_pool())
1692       svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"new_default",
1693                                  &obj, "s", "SVN::Pool");
1694 
1695     return svn_swig_pl_get_current_pool();
1696 }
1697 
1698 /* stream interpolability with io::handle */
1699 
1700 typedef struct io_baton_t {
1701     SV *obj;
1702     IO *io;
1703 } io_baton_t;
1704 
1705 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
io_handle_read(void * baton,char * buffer,apr_size_t * len)1706 static svn_error_t *io_handle_read(void *baton,
1707                                    char *buffer,
1708                                    apr_size_t *len)
1709 {
1710     io_baton_t *io = baton;
1711     MAGIC *mg;
1712 
1713     if ((mg = SvTIED_mg((SV*)io->io, PERL_MAGIC_tiedscalar))) {
1714         SV *ret;
1715         SV *buf = sv_newmortal();
1716 
1717         svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"READ", &ret, "OOz",
1718                                    SvTIED_obj((SV*)io->io, mg),
1719                                    buf, *len);
1720         *len = SvIV(ret);
1721         SvREFCNT_dec(ret);
1722         memmove(buffer, SvPV_nolen(buf), *len);
1723     }
1724     else
1725       *len = PerlIO_read(IoIFP(io->io), buffer, *len);
1726     return SVN_NO_ERROR;
1727 }
1728 
1729 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
io_handle_write(void * baton,const char * data,apr_size_t * len)1730 static svn_error_t *io_handle_write(void *baton,
1731                                     const char *data,
1732                                     apr_size_t *len)
1733 {
1734     io_baton_t *io = baton;
1735     MAGIC *mg;
1736 
1737     if ((mg = SvTIED_mg((SV*)io->io, PERL_MAGIC_tiedscalar))) {
1738         SV *ret, *pv;
1739         pv = sv_2mortal(newSVpvn(data, *len));
1740         svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"WRITE", &ret, "OOz",
1741                                    SvTIED_obj((SV*)io->io, mg), pv, *len);
1742         *len = SvIV(ret);
1743         SvREFCNT_dec(ret);
1744     }
1745     else
1746       *len = PerlIO_write(IoIFP(io->io), data, *len);
1747     return SVN_NO_ERROR;
1748 }
1749 
1750 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
io_handle_close(void * baton)1751 static svn_error_t *io_handle_close(void *baton)
1752 {
1753     io_baton_t *io = baton;
1754     MAGIC *mg;
1755 
1756     if ((mg = SvTIED_mg((SV*)io->io, PERL_MAGIC_tiedscalar))) {
1757       svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"CLOSE", NULL, "O",
1758                                  SvTIED_obj((SV*)io->io, mg));
1759     }
1760     else {
1761       PerlIO_close(IoIFP(io->io));
1762     }
1763 
1764     return SVN_NO_ERROR;
1765 }
1766 
io_handle_cleanup(void * baton)1767 static apr_status_t io_handle_cleanup(void *baton)
1768 {
1769     io_baton_t *io = baton;
1770     SvREFCNT_dec(io->obj);
1771     return APR_SUCCESS;
1772 }
1773 
1774 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_make_stream(svn_stream_t ** stream,SV * obj)1775 svn_error_t *svn_swig_pl_make_stream(svn_stream_t **stream, SV *obj)
1776 {
1777     IO *io;
1778 
1779     if (!SvOK(obj)) {
1780         *stream = NULL;
1781         return SVN_NO_ERROR;
1782     }
1783 
1784     if (obj && sv_isobject(obj)) {
1785       int simple_type = 1;
1786       if (sv_derived_from(obj, "SVN::Stream"))
1787         svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"svn_stream",
1788                                    &obj, "O", obj);
1789         else if (!sv_derived_from(obj, "_p_svn_stream_t"))
1790             simple_type = 0;
1791 
1792         if (simple_type) {
1793             SWIG_ConvertPtr(obj, (void **)stream, _SWIG_TYPE("svn_stream_t *"), 0);
1794             return SVN_NO_ERROR;
1795         }
1796     }
1797 
1798     if (obj && SvROK(obj) && SvTYPE(SvRV(obj)) == SVt_PVGV &&
1799         (io = GvIO(SvRV(obj)))) {
1800         apr_pool_t *pool = svn_swig_pl_get_current_pool();
1801         io_baton_t *iob = apr_palloc(pool, sizeof(io_baton_t));
1802         SvREFCNT_inc(obj);
1803         iob->obj = obj;
1804         iob->io = io;
1805         *stream = svn_stream_create(iob, pool);
1806         svn_stream_set_read2(*stream, NULL /* only full read support */,
1807                              io_handle_read);
1808         svn_stream_set_write(*stream, io_handle_write);
1809         svn_stream_set_close(*stream, io_handle_close);
1810         apr_pool_cleanup_register(pool, iob, io_handle_cleanup,
1811                                   io_handle_cleanup);
1812 
1813     }
1814     else
1815       croak("unknown type for svn_stream_t");
1816 
1817     return SVN_NO_ERROR;
1818 }
1819 
1820 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_ra_lock_callback(void * baton,const char * path,svn_boolean_t do_lock,const svn_lock_t * lock,svn_error_t * ra_err,apr_pool_t * pool)1821 svn_error_t *svn_swig_pl_ra_lock_callback(
1822                     void *baton,
1823                     const char *path,
1824                     svn_boolean_t do_lock,
1825                     const svn_lock_t *lock,
1826                     svn_error_t *ra_err,
1827                     apr_pool_t *pool)
1828 {
1829   if (!SvOK((SV *)baton))
1830       return SVN_NO_ERROR;
1831 
1832   SVN_ERR(svn_swig_pl_callback_thunk(CALL_SV, baton, NULL, "sbSSS",
1833                                      path, do_lock,
1834                                      lock, _SWIG_TYPE("svn_lock_t *"),
1835                                      ra_err, _SWIG_TYPE("svn_error_t *"),
1836                                      pool, POOLINFO));
1837   return SVN_NO_ERROR;
1838 }
1839 
1840 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_from_stream(svn_stream_t * stream)1841 SV *svn_swig_pl_from_stream(svn_stream_t *stream)
1842 {
1843     SV *ret;
1844 
1845     svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"new", &ret, "sS",
1846                                "SVN::Stream", stream, _SWIG_TYPE("svn_stream_t *"));
1847 
1848     return sv_2mortal(ret);
1849 }
1850 
svn_swig_pl_make_file(SV * file,apr_pool_t * pool)1851 apr_file_t *svn_swig_pl_make_file(SV *file, apr_pool_t *pool)
1852 {
1853     apr_file_t *apr_file = NULL;
1854 
1855     if (!SvOK(file) || file == &PL_sv_undef)
1856         return NULL;
1857 
1858     if (SvPOKp(file)) {
1859       apr_file_open(&apr_file, SvPV_nolen(file),
1860                     APR_CREATE | APR_READ | APR_WRITE,
1861                     APR_OS_DEFAULT,
1862                     pool);
1863     } else if (SvROK(file) && SvTYPE(SvRV(file)) == SVt_PVGV) {
1864         apr_status_t status;
1865 #ifdef WIN32
1866         apr_os_file_t osfile = (apr_os_file_t)
1867           _get_osfhandle(PerlIO_fileno(IoIFP(sv_2io(file))));
1868 #else
1869         apr_os_file_t osfile = PerlIO_fileno(IoIFP(sv_2io(file)));
1870 #endif
1871         status = apr_os_file_put(&apr_file, &osfile,
1872                                  O_CREAT | O_WRONLY, pool);
1873         if (status)
1874             return NULL;
1875     }
1876     return apr_file;
1877 }
1878 
cleanup_refcnt(void * data)1879 static apr_status_t cleanup_refcnt(void *data)
1880 {
1881     SV *sv = data;
1882     SvREFCNT_dec(sv);
1883     return APR_SUCCESS;
1884 }
1885 
svn_swig_pl_hold_ref_in_pool(apr_pool_t * pool,SV * sv)1886 void svn_swig_pl_hold_ref_in_pool(apr_pool_t *pool, SV *sv)
1887 {
1888     SvREFCNT_inc(sv);
1889     apr_pool_cleanup_register(pool, sv, cleanup_refcnt, apr_pool_cleanup_null);
1890 }
1891 
1892 /* NOTE: calls back into Perl (by calling svn_swig_pl_callback_thunk) */
svn_swig_pl_from_md5(unsigned char * digest)1893 SV *svn_swig_pl_from_md5(unsigned char *digest)
1894 {
1895     SV *ret;
1896 
1897     svn_swig_pl_callback_thunk(CALL_METHOD, (void *)"new", &ret, "sS",
1898                                "SVN::MD5", digest,
1899                                _SWIG_TYPE("unsigned char *"));
1900 
1901     return sv_2mortal(ret);
1902 }
1903