File Coverage

Param.xs
Criterion Covered Total %
statement 110 162 67.9
branch 69 114 60.5
condition n/a
subroutine n/a
pod n/a
total 179 276 64.8


line stmt bran cond sub pod time code
1             /* --8<--8<--8<--8<--
2             *
3             * Copyright (C) 2006 Smithsonian Astrophysical Observatory
4             *
5             * This file is part of CIAO-Lib-Param
6             *
7             * CIAO-Lib-Param is free software; you can redistribute it and/or
8             * modify it under the terms of the GNU General Public License
9             * as published by the Free Software Foundation; either version 2
10             * of the License, or (at your option) any later version.
11             *
12             * CIAO-Lib-Param is distributed in the hope that it will be useful,
13             * but WITHOUT ANY WARRANTY; without even the implied warranty of
14             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             * GNU General Public License for more details.
16             *
17             * You should have received a copy of the GNU General Public License
18             * along with this program; if not, write to the
19             * Free Software Foundation, Inc.
20             * 51 Franklin Street, Fifth Floor
21             * Boston, MA 02110-1301, USA
22             *
23             * -->8-->8-->8-->8-- */
24              
25             #include "EXTERN.h"
26             #include "perl.h"
27             #include "XSUB.h"
28              
29             /* Global Data */
30              
31             #define MY_CXT_KEY "CIAO::Lib::Param::_guts" XS_VERSION
32              
33             typedef struct {
34             int parerr;
35             int level;
36             char* errmsg;
37             } my_cxt_t;
38              
39             START_MY_CXT
40              
41              
42              
43             #include "ppport.h"
44              
45             #ifdef FLAT_INCLUDES
46             #include
47             #else
48             #include
49             #endif
50              
51             /* yes, this is gross, but it beats including pfile.h */
52             extern int parerr;
53              
54             /* no choice here; these aren't prototyped anywhere from pfile.c */
55             typedef void (*vector)();
56             vector paramerract( void (*newact)() );
57              
58             /* this is definitely overkill, as this could (and was) handled
59             transparently by the XS typemap code. At one point it
60             was thought that per-object data was required and the code
61             was converted to use this structure as the basis for the
62             object, rather than simply blessing the pointer to the paramfile
63             structure
64             */
65             typedef struct PFile
66             {
67             paramfile *pf;
68             } PFile;
69              
70             /* needed for typemap magic */
71             typedef PFile* CIAO_Lib_ParamPtr;
72             typedef pmatchlist CIAO_Lib_Param_MatchPtr;
73              
74             /* use Perl to get temporary space in interface routines; it'll
75             get garbage collected automatically */
76             static void *
77 34           get_mortalspace( int nbytes )
78             {
79 34           SV *mortal = sv_2mortal( NEWSV(0, nbytes ) );
80 34           char *ptr = SvPVX( mortal );
81              
82             /* set the extra NULL byte that Perl gives us to NULL
83             to allow easy string overflow checking */
84 34           ptr[nbytes] = '\0';
85              
86 34           return ptr;
87             }
88              
89              
90             static SV*
91 2           carp_shortmess( char* message )
92             {
93             SV* short_message;
94             int count;
95              
96 2           dSP;
97 2           ENTER ;
98 2           SAVETMPS ;
99              
100             /* ensure that Carp is loaded */
101 2           load_module( PERL_LOADMOD_NOIMPORT, newSVpvn( "Carp", 4 ), (SV*) NULL );
102              
103 2 50         PUSHMARK(SP);
104 2 50         XPUSHs( sv_2mortal(newSVpv(message,0)) );
105 2           PUTBACK;
106              
107             /* make sure there's something to work with */
108 2           count = call_pv( "Carp::shortmess", G_SCALAR );
109              
110 2           SPAGAIN ;
111              
112 2 50         if ( 1 != count )
113 0           croak( "internal error passing message to Carp::shortmess" );
114              
115 2           short_message = newSVsv( POPs );
116              
117 2           PUTBACK ;
118 2 50         FREETMPS ;
119 2           LEAVE ;
120              
121 2           return short_message;
122             }
123              
124              
125             /* propagate the cxcparam error value up to Perl.
126             this is used to cause a croak at the Perl level (see Param.pm for
127             */
128             static void
129 80           croak_on_parerr( void )
130             {
131             dMY_CXT;
132              
133             SV *sv;
134              
135             /* use parerr if specified; else use MY_CXT.parerr. The latter is
136             available if c_paramerr was called. some cxcparam routines
137             don't call c_paramerr. for those that don't, all errors are fatal
138             */
139              
140 80 100         if ( parerr )
141             {
142 1           MY_CXT.parerr = parerr;
143 1           MY_CXT.level = 1;
144             }
145              
146             /* only non-zero levels are fatal */
147 80 100         if ( MY_CXT.parerr && MY_CXT.level)
    50          
148             {
149             SV* sv_error;
150 2           HV* hash = newHV();
151 2           char *errstr = paramerrstr();
152 2 100         char *error = MY_CXT.errmsg ? MY_CXT.errmsg : errstr;
153              
154             /* construct exception object prior to throwing exception */
155              
156 2           hv_store( hash, "errno" , 5, newSViv(MY_CXT.parerr), 0 );
157 2           hv_store( hash, "error" , 5, carp_shortmess(error), 0 );
158 2           hv_store( hash, "errstr", 6, newSVpv(errstr, 0), 0 );
159 2 100         hv_store( hash, "errmsg", 6, MY_CXT.errmsg ? newSVpv(MY_CXT.errmsg, 0) : &PL_sv_undef, 0 );
160              
161             /* reset internal parameter error */
162 2           parerr = MY_CXT.parerr = 0;
163 2           Safefree( MY_CXT.errmsg );
164 2           MY_CXT.errmsg = NULL;
165              
166             /* setup exception object and throw it*/
167             {
168 2           SV* errsv = get_sv("@", TRUE);
169 2           sv_setsv( errsv, sv_bless( newRV_noinc((SV*) hash),
170             gv_stashpv("CIAO::Lib::Param::Error", 1 ) ) );
171             }
172 2           croak( Nullch );
173              
174             }
175              
176             /* here if level == 0 */
177 78 50         if ( MY_CXT.parerr )
178             {
179 0           parerr = MY_CXT.parerr = 0;
180 0           Safefree( MY_CXT.errmsg );
181 0           MY_CXT.errmsg = NULL;
182 0           MY_CXT.level = 0;
183             }
184              
185 78           }
186              
187             /* The replacement error message handling routine for cxcparam.
188             This is put in place in the BOOT: section
189             Note that both paramerrstr() and c_paramerr reset parerr,
190             so we need to keep a local copy.
191             */
192             static void
193 1           perl_paramerr( int level, char *message, char *name )
194             {
195             dMY_CXT;
196             SV* sv;
197             char *errstr;
198             int len;
199              
200             /* save parerr before call to paramerrstr(), as that will
201             reset it */
202 1           MY_CXT.parerr = parerr;
203 1           errstr = paramerrstr();
204              
205 1           len = strlen(errstr) + strlen(message) + strlen(name) + 5;
206              
207 1 50         if ( MY_CXT.errmsg )
208 0           Renew( MY_CXT.errmsg, len, char );
209             else
210 1           New( 0, MY_CXT.errmsg, len, char );
211              
212 1           MY_CXT.level = level;
213 1           sprintf( MY_CXT.errmsg, "%s: %s: %s", message, errstr, name );
214              
215             /* a level of 0 is non-fatal. however, it should be passed up to
216             the caller to handle, and that's not yet implemented. currently
217             cxcparam only issues a level 0 message prior to prompting for
218             a replacement value of a parameter, and since that always
219             goes out to the terminal, we output level 0 messages to
220             stderr and reset parerr so that they are not treated
221             as errors in croak_on_parerr */
222              
223 1 50         if ( 0 == level )
224             {
225 0           fprintf( stderr, "%s\n", MY_CXT.errmsg );
226 0           MY_CXT.parerr = parerr = 0;
227             }
228              
229 1           }
230              
231              
232             MODULE = CIAO::Lib::Param::Match PACKAGE = CIAO::Lib::Param::Match PREFIX = pmatch
233              
234             void
235             DESTROY(mlist)
236             CIAO_Lib_Param_MatchPtr mlist
237             CODE:
238 0           pmatchclose(mlist);
239              
240             MODULE = CIAO::Lib::Param::Match PACKAGE = CIAO::Lib::Param::MatchPtr PREFIX = pmatch
241              
242             int
243             pmatchlength(mlist)
244             CIAO_Lib_Param_MatchPtr mlist
245              
246             char *
247             pmatchnext(mlist)
248             CIAO_Lib_Param_MatchPtr mlist
249              
250              
251             void
252             pmatchrewind(mlist)
253             CIAO_Lib_Param_MatchPtr mlist
254              
255              
256             MODULE = CIAO::Lib::Param PACKAGE = CIAO::Lib::Param
257              
258             BOOT:
259             {
260             MY_CXT_INIT;
261 3           MY_CXT.parerr = 0;
262 3           MY_CXT.level = 0;
263 3           MY_CXT.errmsg = NULL;
264 3           set_paramerror(0); /* Don't exit on error */
265 3           paramerract((vector) perl_paramerr);
266             }
267              
268             CIAO_Lib_ParamPtr
269             open(filename, mode, ...)
270             char * filename
271             const char * mode
272             PREINIT:
273 14           int argc = 0;
274 14           char **argv = NULL;
275             CODE:
276 14           argc = items - 2;
277 14 50         if ( argc )
278             {
279             int i;
280 14           argv = get_mortalspace( argc * sizeof(*argv) );
281 30 100         for ( i = 2 ; i < items ; i++ )
282             {
283 16 100         argv[i-2] = SvOK(ST(i)) ? (char*)SvPV_nolen(ST(i)) : (char*)NULL;
    50          
    50          
    50          
284             }
285             }
286 14           RETVAL = New( 0, RETVAL, 1, PFile );
287 14           RETVAL->pf = paramopen(filename, argv, argc, mode);
288 14 100         if ( NULL == RETVAL->pf )
289             {
290 1           Safefree(RETVAL);
291 1           RETVAL = NULL;
292 1           croak_on_parerr();
293             }
294             OUTPUT:
295             RETVAL
296              
297             char *
298             pfind(name, mode, extn, path)
299             char * name
300             char * mode
301             char * extn
302             char * path
303             CODE:
304 0           RETVAL = paramfind( name, mode, extn, path );
305 0           croak_on_parerr();
306             OUTPUT:
307             RETVAL
308              
309             MODULE = CIAO::Lib::Param PACKAGE = CIAO::Lib::ParamPtr
310              
311             void
312             DESTROY(pfile)
313             CIAO_Lib_ParamPtr pfile
314             CODE:
315 13 50         if ( pfile->pf )
316 13           paramclose(pfile->pf);
317 13           Safefree(pfile);
318 13           croak_on_parerr();
319              
320             void
321             info( pfile, name )
322             CIAO_Lib_ParamPtr pfile
323             char * name
324             PREINIT:
325 0           char * mode = get_mortalspace( SZ_PFLINE );
326 0           char * type = get_mortalspace( SZ_PFLINE );
327 0           char * value = get_mortalspace( SZ_PFLINE );
328 0           char * min = get_mortalspace( SZ_PFLINE );
329 0           char * max = get_mortalspace( SZ_PFLINE );
330 0           char * prompt = get_mortalspace( SZ_PFLINE );
331             int result;
332             PPCODE:
333 0 0         if ( ParamInfo( pfile->pf, name, mode, type,
334             value, min, max, prompt ) )
335             {
336 0 0         EXTEND(SP, 6);
337 0           PUSHs(sv_2mortal(newSVpv(mode, 0)));
338 0           PUSHs(sv_2mortal(newSVpv(type, 0)));
339 0           PUSHs(sv_2mortal(newSVpv(value, 0)));
340 0           PUSHs(sv_2mortal(newSVpv(min, 0)));
341 0           PUSHs(sv_2mortal(newSVpv(max, 0)));
342 0           PUSHs(sv_2mortal(newSVpv(prompt, 0)));
343             }
344             else
345             {
346 0           croak( "parameter %s doesn't exist", name );
347             }
348 0           croak_on_parerr();
349              
350              
351             CIAO_Lib_Param_MatchPtr
352             match(pfile, ptemplate)
353             CIAO_Lib_ParamPtr pfile
354             char * ptemplate
355             CODE:
356 2           RETVAL = pmatchopen( pfile->pf, ptemplate );
357 2           croak_on_parerr();
358             OUTPUT:
359             RETVAL
360              
361              
362              
363             MODULE = CIAO::Lib::Param PACKAGE = CIAO::Lib::ParamPtr PREFIX = param
364              
365              
366             char *
367             paramgetpath(pfile)
368             CIAO_Lib_ParamPtr pfile
369             CODE:
370 0           paramgetpath( pfile->pf );
371             CLEANUP:
372 0 0         if (RETVAL) Safefree(RETVAL);
373 0           croak_on_parerr();
374              
375              
376             MODULE = CIAO::Lib::Param PACKAGE = CIAO::Lib::ParamPtr PREFIX = p
377              
378             int
379             paccess(pfile, pname)
380             CIAO_Lib_ParamPtr pfile
381             char * pname
382             CODE:
383 5           paccess( pfile->pf, pname );
384             CLEANUP:
385 5           croak_on_parerr();
386              
387             SV*
388             pgetb(pfile, pname)
389             CIAO_Lib_ParamPtr pfile
390             char * pname
391             CODE:
392 2           ST(0) = sv_newmortal();
393 2 100         sv_setsv( ST(0), pgetb( pfile->pf, pname ) ? &PL_sv_yes : &PL_sv_no );
394 2           croak_on_parerr();
395              
396             short
397             pgets(pfile, pname)
398             CIAO_Lib_ParamPtr pfile
399             char * pname
400             CODE:
401 0           RETVAL = pgets( pfile->pf, pname );
402 0           croak_on_parerr();
403             OUTPUT:
404             RETVAL
405              
406             int
407             pgeti(pfile, pname)
408             CIAO_Lib_ParamPtr pfile
409             char * pname
410             CODE:
411 0           RETVAL = pgeti( pfile->pf, pname );
412 0           croak_on_parerr();
413             OUTPUT:
414             RETVAL
415              
416             float
417             pgetf(pfile, pname)
418             CIAO_Lib_ParamPtr pfile
419             char * pname
420             CODE:
421 0           RETVAL = pgetf( pfile->pf, pname );
422 0           croak_on_parerr();
423             OUTPUT:
424             RETVAL
425              
426             double
427             pgetd(pfile, pname)
428             CIAO_Lib_ParamPtr pfile
429             char * pname
430             CODE:
431 0           RETVAL = pgetd( pfile->pf, pname );
432 0           croak_on_parerr();
433             OUTPUT:
434             RETVAL
435              
436             SV*
437             get(pfile, pname)
438             CIAO_Lib_ParamPtr pfile
439             char * pname
440             PREINIT:
441             char type[SZ_PFLINE];
442             CODE:
443 38           ST(0) = sv_newmortal();
444 38 50         if ( ParamInfo( pfile->pf, pname, NULL, type, NULL, NULL, NULL, NULL ))
445             {
446 38 100         if ( 0 == strcmp( "b", type ) )
447             {
448 19 100         sv_setsv( ST(0),
449             pgetb( pfile->pf, pname ) ? &PL_sv_yes : &PL_sv_no );
450             }
451             else
452             {
453             char *str;
454 19           size_t buflen = 0;
455 19           size_t len = 0;
456 38 100         while( len == buflen )
457             {
458 19           buflen += SZ_PFLINE;
459 19           str = get_mortalspace( buflen );
460 19           pgetstr( pfile->pf, pname, str, buflen );
461 19           len = strlen( str );
462             }
463 38           sv_setpv(ST(0), str);
464             }
465             }
466             else
467 0           XSRETURN_UNDEF;
468             CLEANUP:
469 38           croak_on_parerr();
470              
471              
472             char *
473             pgetstr(pfile, pname )
474             CIAO_Lib_ParamPtr pfile
475             char * pname
476             PREINIT:
477             char* str;
478 1           size_t buflen = 0;
479 1           size_t len = 0;
480             CODE:
481 1           RETVAL = NULL;
482 2 100         while( len == buflen )
483             {
484 1           buflen += SZ_PFLINE;
485 1           str = get_mortalspace( buflen );
486 1           pgetstr( pfile->pf, pname, str, buflen );
487 1           len = strlen( str );
488             }
489 1           RETVAL = str;
490 1           croak_on_parerr();
491             OUTPUT:
492             RETVAL
493              
494             void
495             pputb(pfile, pname, value)
496             CIAO_Lib_ParamPtr pfile
497             char * pname
498             int value
499             ALIAS:
500             setb = 1
501             CODE:
502 0           pputb( pfile->pf, pname, value );
503 0           croak_on_parerr();
504              
505              
506             void
507             pputd(pfile, pname, value)
508             CIAO_Lib_ParamPtr pfile
509             char * pname
510             double value
511             ALIAS:
512             setd = 1
513             CODE:
514 0           pputd( pfile->pf, pname, value );
515 0           croak_on_parerr();
516              
517             void
518             pputi(pfile, pname, value)
519             CIAO_Lib_ParamPtr pfile
520             char * pname
521             int value
522             ALIAS:
523             seti = 1
524             CODE:
525 0           pputi( pfile->pf, pname, value );
526 0           croak_on_parerr();
527              
528             void
529             pputs(pfile, pname, value)
530             CIAO_Lib_ParamPtr pfile
531             char * pname
532             short value
533             ALIAS:
534             sets = 1
535             CODE:
536 0           pputs( pfile->pf, pname, value );
537 0           croak_on_parerr();
538              
539             void
540             pputstr(pfile, pname, value)
541             CIAO_Lib_ParamPtr pfile
542             char * pname
543             char * value
544             ALIAS:
545             setstr = 1
546             CODE:
547 0           pputstr( pfile->pf, pname, value );
548 0           croak_on_parerr();
549              
550             void
551             put(pfile, pname, value)
552             CIAO_Lib_ParamPtr pfile
553             char * pname
554             SV* value
555             ALIAS:
556             set = 1
557             PREINIT:
558             char type[SZ_PFLINE];
559             CODE:
560             /* if the parameter exists and is a boolean,
561             translate from numerics to string if it looks like a
562             number, else let pset handle it
563             */
564 18 50         if ( ParamInfo( pfile->pf, pname, NULL, type, NULL, NULL, NULL, NULL ) &&
    100          
565 15 100         0 == strcmp( "b", type ) &&
566 23 100         ( looks_like_number( value ) ||
567 8           0 == sv_len(value )
568             )
569             )
570             {
571 9 50         pputb(pfile->pf, pname, SvTRUE(value) );
    50          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    100          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
572             }
573             else
574             {
575 9 50         pputstr(pfile->pf, pname, SvOK(value) ? (char*)SvPV_nolen(value) : (char*)NULL );
    0          
    0          
    50          
576             }
577             CLEANUP:
578 18           croak_on_parerr();
579              
580              
581             char *
582             evaluateIndir(pfile, name, val)
583             CIAO_Lib_ParamPtr pfile
584             char * name
585             char * val
586             CODE:
587 0           RETVAL = evaluateIndir(pfile->pf, name, val);
588             CLEANUP:
589 0 0         if ( RETVAL ) Safefree( RETVAL );
590 0           croak_on_parerr();