1 /*
2 
3   AST.xs
4 
5   Copyright (C) 2004-2005 Tim Jenness. All Rights Reserved.
6 
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
11 
12 This program is distributed in the hope that it will be useful,but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14 PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place,Suite 330, Boston, MA  02111-1307, USA
19 
20 */
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 #include "EXTERN.h"   /* std perl include */
26 #include "perl.h"     /* std perl include */
27 #include "XSUB.h"     /* XSUB include */
28 #include "ppport.h"
29 #ifdef __cplusplus
30 }
31 #endif
32 
33 /* for some reason ppport.h does not currently have CopFILE defined */
34 #ifndef CopFILE
35 #define CopFILE(s)  "<unknown>"
36 #endif
37 #ifndef CopLINE
38 #define CopLINE(s)  -1
39 #endif
40 
41 /* typedef some common types so that the typemap can bless constants
42    into correct namespaces */
43 
44 #include <limits.h>
45 
46 typedef int StatusType;
47 typedef int WcsMapType;
48 
49 #include "ast.h"
50 #include "grf.h"
51 
52 /* Older versions of AST can require Fortran, so we add dummy main
53    needed by, eg, g95 */
54 #if ( AST_MAJOR_VERS < 4 )
MAIN_()55 void MAIN_ () {}
MAIN__()56 void MAIN__ () {}
57 #endif
58 
59 
60 /* The following definitions are required for backwards compatible
61    Since AST version 2 does not have these.
62 */
63 
64 #if ( AST_MAJOR_VERS >= 2 )
65 # define HASSPECFRAME
66 # define HASSPECMAP
67 # define HASSPECADD
68 # define HASSETREFPOS
69 # define HASGETREFPOS
70 # define HASGETACTIVEUNIT
71 # define HASSETACTIVEUNIT
72 #else
73 typedef void AstSpecFrame;
74 typedef void AstSpecMap;
75 #endif
76 
77 #if ( AST_MAJOR_VERS >= 3 )
78 #define HASPOLYMAP
79 #define HASGRISMMAP
80 #define HASSHIFTMAP
81 #define HASRATE
82 #else
83 typedef void AstPolyMap;
84 typedef void AstGrismMap;
85 typedef void AstShiftMap;
86 #endif
87 
88 #if ( (AST_MAJOR_VERS == 3 && AST_MINOR_VERS >= 1) || AST_MAJOR_VERS >= 4 )
89 #define HASXMLCHAN
90 #else
91 typedef void AstXmlChan;
92 #endif
93 
94 #if ( (AST_MAJOR_VERS == 5 && AST_MINOR_VERS >= 2) || AST_MAJOR_VERS >= 6 )
95 #define HASSTCSCHAN
96 #else
97 typedef void AstStcsChan;
98 #endif
99 
100 #if ( (AST_MAJOR_VERS == 3 && AST_MINOR_VERS >= 2) || AST_MAJOR_VERS >= 4 )
101 #define HASTRANMAP
102 #define HASPUTCARDS
103 #define HASESCAPES
104 #else
105 typedef void AstTranMap;
106 #endif
107 
108 #if ( (AST_MAJOR_VERS == 3 && AST_MINOR_VERS >= 4) || AST_MAJOR_VERS >= 4 )
109 #define HASDSBSPECFRAME
110 #else
111 typedef void AstDSBSpecFrame;
112 #endif
113 
114 #if ( (AST_MAJOR_VERS == 3 && AST_MINOR_VERS >= 5) || AST_MAJOR_VERS >= 4 )
115 #define HASLINEARAPPROX
116 #define HASSETFITS
117 #define HASRATEMAP
118 #define HASKEYMAP
119 #define HASFLUXFRAME
120 #define HASSPECFLUXFRAME
121 #define HASREGION
122 #else
123 typedef void AstRateMap;
124 typedef void AstKeyMap;
125 typedef void AstFluxFrame;
126 typedef void AstSpecFluxFrame;
127 typedef void AstRegion;
128 typedef void AstBox;
129 typedef void AstCircle;
130 typedef void AstEllipse;
131 typedef void AstNullRegion;
132 typedef void AstPolygon;
133 typedef void AstInterval;
134 typedef void CmpRegion;
135 #endif
136 
137 #if ( (AST_MAJOR_VERS == 3 && AST_MINOR_VERS >= 7) || AST_MAJOR_VERS >= 4 )
138 #define HASTIMEFRAME
139 #define HASTIMEMAP
140 #else
141 typedef void AstTimeFrame;
142 typedef void AstTimeMap;
143 #endif
144 
145 /* between v3.0 and v3.4 astRate returned the second derivative */
146 #if ( AST_MAJOR_VERS == 3 && AST_MINOR_VERS < 5 )
147 #define RATE_HAS_SECOND_DERIVATIVE 1
148 #endif
149 
150 #if ( (AST_MAJOR_VERS == 4 && AST_MINOR_VERS >= 1) || AST_MAJOR_VERS >= 5 )
151 #define HASMAPSPLIT
152 #else
153 #endif
154 
155 #if ( (AST_MAJOR_VERS == 5 && AST_MINOR_VERS >= 3) || AST_MAJOR_VERS >= 6 )
156 #define HASMAPPUTU
157 #define HASHASATTRIBUTE
158 #else
159 #endif
160 
161 #if ( (AST_MAJOR_VERS == 5 && AST_MINOR_VERS >= 4) || AST_MAJOR_VERS >= 6 )
162 #define HASKEYMAPSHORT
163 #else
164 #endif
165 
166 #if ( (AST_MAJOR_VERS == 7 && AST_MINOR_VERS >= 2) || AST_MAJOR_VERS >= 8 )
167 #define HASMAPDEFINED
168 #else
169 #endif
170 
171 
172 /* Helper functions */
173 #include "arrays.h"
174 #include "astTypemap.h"
175 
pack1Dchar(AV * avref)176 static char ** pack1Dchar( AV * avref ) {
177   int i;
178   SV ** elem;
179   char ** outarr;
180   int len;
181   STRLEN linelen;
182 
183   /* number of elements */
184   len  = av_len( avref ) + 1;
185   /* Temporary storage */
186   outarr = get_mortalspace( len,'v');
187 
188   for (i=0; i<len; i++) {
189     elem = av_fetch( avref, i, 0);
190     if (elem == NULL ) {
191       /* undef */
192     } else {
193       outarr[i] = SvPV( *elem, linelen);
194     }
195   }
196   return outarr;
197 }
198 
pack1DAstObj(AV * avref)199 static AstObject ** pack1DAstObj( AV * avref ) {
200   int i;
201   SV ** elem;
202   AstObject ** outarr;
203   int len;
204 
205   /* number of elements */
206   len  = av_len( avref ) + 1;
207   /* Temporary storage - array of pointers */
208   outarr = get_mortalspace( len,'v');
209 
210   for (i=0; i<len; i++) {
211     elem = av_fetch( avref, i, 0);
212     if (elem == NULL ) {
213       /* undef */
214     } else {
215       /* Now need to convert this SV** to an AstObject */
216       if (sv_derived_from(*elem, "Starlink::AST")) {
217 	    IV tmpiv = extractAstIntPointer( *elem );
218 	    outarr[i] = INT2PTR(AstObject *,tmpiv);
219       } else {
220         Perl_croak( aTHX_ "Array contains non-Starlink::AST variables");
221       }
222     }
223   }
224   return outarr;
225 }
226 
227 /* This routine should throw an exception of a different
228    class depending on the value of the AST status. For
229    now we croak with the error message.
230 
231    We deliberately try to stay in C here rather than
232    add to the complexity by calling out into perl.
233 */
234 
astThrowException(int status,AV * errorstack)235 static void astThrowException ( int status, AV* errorstack ) {
236   size_t i;
237   size_t nelem;
238 
239   SV * errsv = sv_2mortal( newSVpvn("", 0) );
240 
241   nelem = av_len( errorstack );
242   for (i = 0; i <= nelem; i++ ) {
243     SV ** elem = av_fetch( errorstack, i, 0);
244     if (elem != NULL ) {
245       sv_catpv( errsv, "- ");
246       sv_catsv( errsv, (SV*)*elem);
247       if (i != nelem) sv_catpv( errsv, "\n");
248     }
249   }
250   Perl_croak( aTHX_ "%s", SvPV_nolen( errsv ) );
251 }
252 
253 /* Callbacks */
254 
255 /* sourceWrap is called by the fitschan constructor immediately and not
256    by the Read method. This means that there are no worries about
257    reference counting or keeping copies of the function around.
258  */
259 
sourceWrap(const char * (* source)(),int * status)260 static char *sourceWrap( const char *(*source)(), int *status ) {
261   dSP;
262   SV * cb;
263   SV * myobject;
264   SV * retsv;
265   int count;
266   STRLEN len;
267   char * line;
268   char * retval = NULL;
269 
270   /* Return directly if ast status is set. */
271   if ( !astOK ) return NULL;
272   if ( source == NULL ) {
273     astError( AST__INTER, "source function called without Perl callback");
274     return NULL;
275   }
276 
277   /* Need to cast the source argument to a SV* and extract the callback from the object */
278   myobject = (SV*) source;
279   cb = getPerlObjectAttr( myobject, "_source" );
280   if (cb == NULL) {
281     astError( AST__INTER, "Callback in channel 'source' not defined!");
282     return NULL;
283   }
284   cb = SvRV( cb );
285 
286   /* call the callback with the supplied line */
287   ENTER;
288   SAVETMPS;
289 
290   PUSHMARK(sp);
291   PUTBACK;
292 
293   count = call_sv( cb, G_NOARGS | G_SCALAR | G_EVAL );
294 
295   ReportPerlError( AST__INTER );
296 
297   SPAGAIN ;
298 
299   if (astOK) {
300     if (count != 1) {
301       astError( AST__INTER, "Returned more than one arg from channel source");
302     } else {
303       retsv = POPs;
304 
305       if (SvOK(retsv)) {
306 	line = SvPV(retsv, len);
307 
308 	/* The sourceWrap function must return the line in memory
309 	   allocated using the AST memory allocator */
310 	retval = astMalloc( len + 1 );
311 	if ( retval != NULL ) {
312 	  strcpy( retval, line );
313 	}
314       } else {
315 	retval = NULL;
316       }
317     }
318   }
319 
320   PUTBACK;
321   FREETMPS;
322   LEAVE;
323 
324   return retval;
325 }
326 
sinkWrap(void (* sink)(const char *),const char * line,int * status)327 static void sinkWrap( void (*sink)(const char *), const char *line, int *status ) {
328   dSP;
329   SV * cb;
330   SV * myobject;
331 
332   /* Return directly if ast status is set. */
333   if ( !astOK ) return;
334 
335   /* Need to cast the sink argument to a SV*  */
336   myobject = (SV*) sink;
337 
338   cb = getPerlObjectAttr( myobject, "_sink" );
339 
340   if (cb == NULL) {
341     astError( AST__INTER, "Callback in channel 'sink' not defined!");
342     return;
343   }
344 
345 
346   /* call the callback with the supplied line */
347   ENTER;
348   SAVETMPS;
349 
350   PUSHMARK(sp);
351   XPUSHs( sv_2mortal( newSVpv( (char*)line, strlen(line) )));
352   PUTBACK;
353 
354   call_sv( SvRV(cb), G_DISCARD | G_VOID | G_EVAL );
355 
356   ReportPerlError( AST__INTER );
357 
358   FREETMPS;
359   LEAVE;
360 
361 }
362 
363 
364 /* Need to allocate a mutex to prevent threads accessing
365    the AST simultaneously. May need to protect this from
366    non-threaded perl */
367 
368 #ifdef USE_ITHREADS
369 static perl_mutex AST_mutex;
370 #endif
371 
372 /* An array to store the messages coming from the error system */
373 AV* ErrBuff;
374 
375 /* We need to make sure that ast routines are called in a thread-safe
376    manner since the underlying AST library is not thread-safe because
377    of the error system. Use Mark's JNIAST technique */
378 
379 #define ASTCALL(code) \
380   STMT_START { \
381     int my_xsstatus_val = 0; \
382     int *my_xsstatus = &my_xsstatus_val; \
383     int *old_ast_status; \
384     AV* local_err; \
385     MUTEX_LOCK(&AST_mutex); \
386     My_astClearErrMsg(); \
387     old_ast_status = astWatch( my_xsstatus ); \
388     code \
389     astWatch( old_ast_status ); \
390     /* Need to remove the MUTEX before we croak [but must copy the error buffer] */ \
391     My_astCopyErrMsg( &local_err, *my_xsstatus ); \
392     MUTEX_UNLOCK(&AST_mutex); \
393     if ( *my_xsstatus != 0 ) { \
394       astThrowException( *my_xsstatus, local_err ); \
395     } \
396   } STMT_END;
397 
398 
399 /* When we call plot routines, we need to register the plot object
400    in a global variable so that the plotting infrastructure can get
401    at the callbacks */
402 
403 #define PLOTCALL(grfobject,code) \
404   ASTCALL( \
405     Perl_storeGrfObject( grfobject ); \
406     code \
407     Perl_clearGrfObject(); \
408   )
409 
410 /* This is the error handler.
411  Store error messages in an array. Need to worry about thread-local storage
412  very soon.
413 
414  This symbol must be available to the AST routines as we are deliberately
415  replacing the AST error handler.
416  */
417 
astPutErr_(int status,const char * message)418 void astPutErr_ ( int status, const char * message ) {
419   /* the av_clear decrements the refcnt of the SV entries */
420   av_push(ErrBuff, newSVpv((char*)message, 0) );
421 }
422 
My_astClearErrMsg()423 static void My_astClearErrMsg () {
424   av_clear( ErrBuff );
425 }
426 
427 /* routine to copy the error messages from the global array to a private
428    array so that we can release the Mutex before the exception is thrown.
429    Creates a new mortal AV and populates it.
430 
431    This is required because astPutErr can only use the static version
432    of the array.
433 
434    Does not try to do anything if status is 0
435  */
436 
My_astCopyErrMsg(AV ** newbuff,int status)437 static void My_astCopyErrMsg ( AV ** newbuff, int status ) {
438   size_t i;
439   size_t nelem;
440   if (status == 0) return;
441 
442   *newbuff = newAV();
443   sv_2mortal((SV*)*newbuff);
444   nelem = av_len( ErrBuff );
445   for (i = 0; i <= nelem ; i++ ) {
446     SV ** elem = av_fetch( ErrBuff, i, 0);
447     if (elem != NULL ) {
448       SvREFCNT_inc( *elem ); /* Storing it in a new place so inc reference count */
449       av_push( *newbuff, *elem);
450     }
451   }
452 
453   /* And we no longer need the error array contents */
454   My_astClearErrMsg();
455 
456 }
457 
458 /* Since you can not put CPP code within CPP code inside XS we need
459    to provide a special wrapper routine for astRate */
myAstRate(AstMapping * this,double * cat,int ax1,int ax2,double * d2)460 static void myAstRate ( AstMapping * this, double * cat, int ax1, int ax2,
461                         double * d2) {
462   double RETVAL;
463   dXSARGS;
464 
465 #if RATE_HAS_SECOND_DERIVATIVE
466   ASTCALL(
467     RETVAL = astRate( this, cat, ax1, ax2, d2 );
468   )
469 #else
470   ASTCALL(
471     RETVAL = astRate( this, cat, ax1, ax2 );
472   )
473 #endif
474   if ( RETVAL != AST__BAD ) {
475      XPUSHs(sv_2mortal(newSVnv(RETVAL)));
476 #ifdef RATE_HAS_SECOND_DERIVATIVE
477      XPUSHs(sv_2mortal(newSVnv(*d2)));
478 #endif
479   } else {
480      XSRETURN_EMPTY;
481   }
482 }
483 
484 
485 MODULE = Starlink::AST     PACKAGE = Starlink::AST
486 
487 PROTOTYPES: DISABLE
488 
489 BOOT:
490           MUTEX_INIT(&AST_mutex);
491           ErrBuff = newAV();
492 
493 double
494 AST__BAD()
495  CODE:
496 #ifdef AST__BAD
497     RETVAL = AST__BAD;
498 #else
499     Perl_croak(aTHX_ "Constant AST__BAD not defined\n");
500 #endif
501  OUTPUT:
502   RETVAL
503 
504 int
505 AST__CURRENT()
506  CODE:
507 #ifdef AST__CURRENT
508     RETVAL = AST__CURRENT;
509 #else
510     Perl_croak(aTHX_ "Constant AST__CURRENT not defined\n");
511 #endif
512  OUTPUT:
513   RETVAL
514 
515 int
516 AST__NOFRAME()
517  CODE:
518 #ifdef AST__NOFRAME
519     RETVAL = AST__NOFRAME;
520 #else
521     Perl_croak(aTHX_ "Constant AST__NOFRAME not defined\n");
522 #endif
523  OUTPUT:
524   RETVAL
525 
526 int
527 AST__BASE()
528  CODE:
529 #ifdef AST__BASE
530     RETVAL = AST__BASE;
531 #else
532     Perl_croak(aTHX_ "Constant AST__BASE not defined\n");
533 #endif
534  OUTPUT:
535   RETVAL
536 
537 int
538 AST__ALLFRAMES()
539  CODE:
540 #ifdef AST__ALLFRAMES
541     RETVAL = AST__ALLFRAMES;
542 #else
543     Perl_croak(aTHX_ "Constant AST__ALLFRAMES not defined\n");
544 #endif
545  OUTPUT:
546   RETVAL
547 
548 MODULE = Starlink::AST     PACKAGE = Starlink::AST PREFIX = ast
549 
550 
551 void
552 astBegin()
553  CODE:
554   ASTCALL(
555     astBegin;
556   )
557 
558 
559 void
560 astEnd()
561  CODE:
562   ASTCALL(
563     astEnd;
564   )
565 
566 bool
567 astEscapes( new_value )
568   bool new_value
569  CODE:
570 #ifndef HASESCAPES
571    Perl_croak(aTHX_ "astEscapes: Please upgrade to AST V3.2 or greater");
572 #else
573   RETVAL = astEscapes( new_value );
574 #endif
575  OUTPUT:
576   RETVAL
577 
578 # Can be called as class method or function
579 
580 int
581 astVersion( ... )
582  CODE:
583 #if ( AST_MAJOR_VERS >= 2 )
584   ASTCALL(
585    RETVAL = astVersion;
586   )
587 #else
588    Perl_croak(aTHX_ "astVersion: Please upgrade to AST V2.x or greater");
589 #endif
590  OUTPUT:
591   RETVAL
592 
593 void
594 astIntraReg()
595  CODE:
596    Perl_croak(aTHX_ "astIntraReg Not yet implemented\n");
597 
598 # The following functions are associated with AST internal status
599 # They can only be called from within an AST callback (eg the
600 # graphics system since they do not MUTEX and they do not switch
601 # the internal status variable.
602 
603 # Note the use of _ in name
604 
605 # No need to make this private but we need to make sure
606 # this is called from within a mutex (so a callback is okay)
607 # Call is as _OK. but without changing the current status integer
608 
609 bool
610 ast_OK()
611  CODE:
612   RETVAL = astOK;
613  OUTPUT:
614   RETVAL
615 
616 # Called only from within AST callbacks. No MUTEX locking.
617 
618 void
619 ast_Error( status, message)
620   StatusType status
621   char * message
622  CODE:
623   astError( status, "%s", message);
624 
625 
626 # Call only from within an AST callback
627 
628 void
629 ast_ClearStatus()
630  CODE:
631    astClearStatus;
632 
633 void
634 ast_SetStatus( status )
635   StatusType status
636  CODE:
637    astSetStatus( status );
638 
639 StatusType
640 ast_Status()
641  CODE:
642    RETVAL = astStatus;
643  OUTPUT:
644   RETVAL
645 
646 MODULE = Starlink::AST  PACKAGE = Starlink::AST::Status
647 
648 # Translate status values
649 int
650 value( this )
651   StatusType this
652  CODE:
653   RETVAL = this;
654  OUTPUT:
655   RETVAL
656 
657 MODULE = Starlink::AST  PACKAGE = Starlink::AST::Frame
658 
659 AstFrame *
660 new( class, naxes, options )
661   char * class
662   int naxes
663   char * options
664  CODE:
665   ASTCALL(
666    RETVAL = astFrame( naxes, options );
667   )
668   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
669  OUTPUT:
670   RETVAL
671 
672 MODULE = Starlink::AST  PACKAGE = Starlink::AST::FrameSet
673 
674 AstFrameSet *
675 new( class, frame, options )
676   char * class
677   AstFrame * frame
678   char * options
679  CODE:
680   ASTCALL(
681    RETVAL = astFrameSet( frame, options );
682   )
683   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
684  OUTPUT:
685   RETVAL
686 
687 MODULE = Starlink::AST  PACKAGE = Starlink::AST::CmpFrame
688 
689 AstCmpFrame *
690 new( class, frame1, frame2, options )
691   char * class
692   AstFrame * frame1
693   AstFrame * frame2
694   char * options
695  CODE:
696   ASTCALL(
697    RETVAL = astCmpFrame( frame1, frame2, options );
698   )
699   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
700  OUTPUT:
701   RETVAL
702 
703 MODULE = Starlink::AST  PACKAGE = Starlink::AST::FluxFrame
704 
705 AstFluxFrame *
706 new( class, specval, specfrm, options )
707   char * class
708   double specval
709   AstSpecFrame * specfrm
710   char * options
711  CODE:
712 #ifndef HASKEYMAP
713   Perl_croak(aTHX_ "astFluxFrame: Please upgrade to AST V3.5 or newer");
714 #else
715   ASTCALL(
716    RETVAL = astFluxFrame( specval, specfrm, options );
717   )
718   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
719 #endif
720  OUTPUT:
721   RETVAL
722 
723 MODULE = Starlink::AST  PACKAGE = Starlink::AST::SpecFluxFrame
724 
725 AstSpecFluxFrame *
726 new( class, frame1, frame2, options )
727   char * class
728   AstSpecFrame * frame1
729   AstFluxFrame * frame2
730   char * options
731  CODE:
732 #ifndef HASSPECFLUXFRAME
733   Perl_croak(aTHX_ "astSpecFluxFrame: Please upgrade to AST V3.5 or newer");
734 #else
735   ASTCALL(
736    RETVAL = astSpecFluxFrame( frame1, frame2, options );
737   )
738   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
739 #endif
740  OUTPUT:
741   RETVAL
742 
743 MODULE = Starlink::AST  PACKAGE = Starlink::AST::CmpMap
744 
745 AstCmpMap *
746 new( class, map1, map2, series, options )
747   char * class
748   AstMapping * map1
749   AstMapping * map2
750   int series
751   char * options
752  CODE:
753   ASTCALL(
754    RETVAL = astCmpMap( map1, map2, series, options );
755   )
756   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
757  OUTPUT:
758   RETVAL
759 
760 MODULE = Starlink::AST  PACKAGE = Starlink::AST::Channel
761 
762 # Need to add proper support for the callbacks. Currently rely on the
763 # returned object to keep a reference to the callback.
764 
765 # Note that we use inheritance here so we have to switch on the basis
766 # of the supplied class. Things will get difficult if people start
767 # adding their own subclasses since I am only looking at substring
768 # matches.
769 
770 SV *
771 _new( class, sourcefunc, sinkfunc, options )
772   char * class
773   SV * sourcefunc
774   SV * sinkfunc
775   char * options;
776  PREINIT:
777   SV ** value;
778   SV * sink = NULL;
779   SV * source = NULL;
780   AstChannel * channel;
781   AstFitsChan * fitschan;
782   AstXmlChan * xmlchan;
783   AstStcsChan * stcschan;
784   bool has_source = 0;
785   bool has_sink = 0;
786  CODE:
787   /* create the object without a pointer */
788   RETVAL = createPerlObject( class, NULL );
789 
790   /* Decide whether to register a callback with the sink/source.
791      Do this rather than always registering callback for efficiency reasons
792      and because I am not sure if the presence of a callback affects the
793      behaviour of the channel. */
794 
795   /* First see whether we were given valid callbacks */
796   if (SvOK(sourcefunc) && SvROK(sourcefunc) &&
797         SvTYPE(SvRV(sourcefunc)) == SVt_PVCV) has_source = 1;
798   if (SvOK(sinkfunc) && SvROK(sinkfunc) &&
799         SvTYPE(SvRV(sinkfunc)) == SVt_PVCV) has_sink = 1;
800 
801   if ( has_source || has_sink) {
802     /* Take a reference to the object but do not increment the REFCNT. We
803        Want this to be freed when the perl object disappears. */
804     /* only take one reference */
805 
806     /* For sink functions we have to keep them around in the object
807        since they are called when the object is annulled. */
808     SV * rv = newRV_noinc( SvRV( RETVAL ));
809     if (has_sink) {
810       /* Store reference to object */
811       sink = rv;
812       /* and store the actual sink callback in the object */
813       setPerlObjectAttr( RETVAL, "_sink", newRV_inc( SvRV(sinkfunc) ));
814     }
815 
816     /* In some cases the source routine is called after this constructor
817        returns. We therefore need to store the source function in the object
818        as well. */
819     if (has_source) {
820       /* Store reference to object */
821       source = rv;
822       /* and store the actual sink callback in the object */
823       setPerlObjectAttr( RETVAL, "_source", newRV_inc( SvRV(sourcefunc) ));
824     }
825 
826   }
827 
828   /* Need to use astChannelFor style interface so that we can register
829      a fixed callback and a reference to a CV */
830   if ( strstr( class, "Channel") != NULL) {
831    ASTCALL(
832     channel = astChannelFor( (const char *(*)()) source, sourceWrap,
833                              (void (*)( const char * )) sink, sinkWrap, options );
834    )
835    if (astOK) setPerlAstObject( RETVAL, (AstObject*)channel );
836   } else if (strstr( class, "FitsChan") != NULL) {
837    ASTCALL(
838     fitschan = astFitsChanFor( (const char *(*)()) source, sourceWrap,
839                              (void (*)( const char * )) sink, sinkWrap, options );
840    )
841    if (astOK) setPerlAstObject( RETVAL, (AstObject*)fitschan );
842   } else if (strstr( class, "XmlChan") != NULL ) {
843 #ifndef HASXMLCHAN
844    Perl_croak(aTHX_ "XmlChan: Please upgrade to AST V3.1 or greater");
845 #else
846    ASTCALL(
847     xmlchan = astXmlChanFor( (const char *(*)()) source, sourceWrap,
848                              (void (*)( const char * )) sink, sinkWrap, options );
849    )
850    if (astOK) setPerlAstObject( RETVAL, (AstObject*)xmlchan );
851 #endif
852   } else if (strstr( class, "StcsChan") != NULL ) {
853 #ifndef HASSTCSCHAN
854    Perl_croak(aTHX_ "StcsChan: Please upgrade to AST V5.2 or greater");
855 #else
856    ASTCALL(
857     stcschan = astStcsChanFor( (const char *(*)()) source, sourceWrap,
858                                (void (*)( const char * )) sink, sinkWrap, options );
859    )
860    if (astOK) setPerlAstObject( RETVAL, (AstObject*)stcschan );
861 #endif
862   } else {
863      Perl_croak(aTHX_ "Channel of class %s not recognized.", class );
864   }
865   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
866  OUTPUT:
867   RETVAL
868 
869 
870 MODULE = Starlink::AST  PACKAGE = Starlink::AST::GrismMap
871 
872 AstGrismMap *
873 new( class, options )
874   char * class
875   char * options
876  CODE:
877 #ifndef HASGRISMMAP
878    Perl_croak(aTHX_ "GrismMap: Please upgrade to AST V3.x or greater");
879 #else
880   ASTCALL(
881    RETVAL = astGrismMap( options );
882   )
883   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
884 #endif
885  OUTPUT:
886   RETVAL
887 
888 MODULE = Starlink::AST  PACKAGE = Starlink::AST::IntraMap
889 
890 AstIntraMap *
891 new( class, name, nin, nout, options )
892   char * class
893   char * name
894   int nin
895   int nout
896   char * options
897  CODE:
898   ASTCALL(
899    RETVAL = astIntraMap( name, nin, nout, options );
900   )
901   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
902  OUTPUT:
903   RETVAL
904 
905 MODULE = Starlink::AST  PACKAGE = Starlink::AST::LutMap
906 
907 AstLutMap *
908 new( class, lut, start, inc, options )
909   char * class
910   AV* lut
911   double start
912   double inc
913   char * options
914  PREINIT:
915   int nlut;
916   double * clut;
917  CODE:
918   nlut = av_len( lut ) + 1;
919   clut = pack1D( newRV_noinc((SV*)lut), 'd' );
920   ASTCALL(
921    RETVAL = astLutMap( nlut, clut, start, inc, options );
922   )
923   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
924  OUTPUT:
925   RETVAL
926 
927 MODULE = Starlink::AST  PACKAGE = Starlink::AST::MathMap
928 
929 AstMathMap *
930 new( class, nin, nout, fwd, inv, options )
931   char * class
932   int nin
933   int nout
934   AV* fwd
935   AV* inv
936   char * options
937  PREINIT:
938   int nfwd;
939   int ninv;
940   SV** elem;
941   int i;
942   char ** cfwd;
943   char ** cinv;
944  CODE:
945   nfwd = av_len( fwd ) + 1;
946   ninv = av_len( inv ) + 1;
947   cfwd = pack1Dchar( fwd );
948   cinv = pack1Dchar( inv );
949   RETVAL = astMathMap( nin, nout, nfwd, (const char **)cfwd,
950                        ninv, (const char**)cinv, options );
951   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
952  OUTPUT:
953   RETVAL
954 
955 MODULE = Starlink::AST  PACKAGE = Starlink::AST::MatrixMap
956 
957 # Note that form is derived from the size of matrix
958 
959 AstMatrixMap *
new(class,nin,nout,matrix,options)960 new( class, nin, nout, matrix, options )
961   char * class
962   int nin
963   int nout
964   AV* matrix
965   char * options
966  PREINIT:
967   int len;
968   int form;
969   double * cmatrix;
970  CODE:
971   len = av_len( matrix ) + 1;
972   /* determine form from number of elements */
973   if (len == 0) {
974     form = 2;
975   } else if (len == nin || len == nout ) {
976     form = 1;
977   } else if ( len == (nin * nout ) ) {
978     form = 0;
979   } else {
980     Perl_croak(aTHX_ "MatrixMap: matrix len not consistent with nout/nin");
981   }
982   cmatrix = pack1D(newRV_noinc((SV*)matrix), 'd');
983   ASTCALL(
984    RETVAL = astMatrixMap( nin, nout, form, cmatrix, options );
985   )
986   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
987  OUTPUT:
988   RETVAL
989 
990 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Plot
991 
992 AstPlot *
993 _new( class, frame, graphbox, basebox, options )
994   char * class
995   AstFrame * frame
996   AV* graphbox
997   AV* basebox
998   char * options
999  PREINIT:
1000   int len;
1001   float * cgraphbox;
1002   double * cbasebox;
1003  CODE:
1004   len = av_len( graphbox ) + 1;
1005   if ( len != 4 ) Perl_croak(aTHX_ "GraphBox must contain 4 values" );
1006   len = av_len( basebox ) + 1;
1007   if ( len != 4 ) Perl_croak(aTHX_ "BaseBox must contain 4 values" );
1008   cbasebox = pack1D( newRV_noinc((SV*)basebox), 'd');
1009   cgraphbox = pack1D( newRV_noinc((SV*)graphbox), 'f');
1010   ASTCALL(
1011     RETVAL = astPlot( frame, cgraphbox, cbasebox, options );
1012   )
1013   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1014  OUTPUT:
1015   RETVAL
1016 
1017 MODULE = Starlink::AST   PACKAGE = Starlink::AST::PcdMap
1018 
1019 AstPcdMap *
new(class,disco,pcdcen,options)1020 new( class, disco, pcdcen, options )
1021   char * class
1022   double disco
1023   AV* pcdcen
1024   char * options
1025  PREINIT:
1026   int len;
1027   double * cpcdcen;
1028  CODE:
1029   len = av_len( pcdcen ) + 1;
1030   if (len != 2 ) {
1031     Perl_croak(aTHX_ "Must supply two values to PcdCen");
1032   }
1033   cpcdcen = pack1D(newRV_noinc((SV*)pcdcen), 'd');
1034   ASTCALL(
1035    RETVAL = astPcdMap( disco, cpcdcen, options );
1036   )
1037   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1038  OUTPUT:
1039   RETVAL
1040 
1041 MODULE = Starlink::AST   PACKAGE = Starlink::AST::PermMap
1042 
1043 AstPermMap *
1044 new( class, inperm, outperm, constant, options )
1045   char * class
1046   AV* inperm
1047   AV* outperm
1048   AV* constant
1049   char * options
1050  PREINIT:
1051   int len;
1052   int * coutperm;
1053   int * cinperm;
1054   double * cconstant;
1055   int nin;
1056   int nout;
1057  CODE:
1058   nin = av_len( inperm ) + 1;
1059   if (nin == 0 ) {
1060     /* no values */
1061     cinperm = NULL;
1062   } else {
1063     cinperm = pack1D(newRV_noinc((SV*)inperm), 'i' );
1064   }
1065   nout = av_len( outperm ) + 1;
1066   if (nout == 0 ) {
1067     /* no values */
1068     coutperm = NULL;
1069   } else {
1070     coutperm = pack1D(newRV_noinc((SV*)outperm), 'i' );
1071   }
1072   len = av_len( constant ) + 1;
1073   if (len == 0 ) {
1074     /* no values */
1075     cconstant = NULL;
1076   } else {
1077     cconstant = pack1D(newRV_noinc((SV*)constant), 'd' );
1078   }
1079   ASTCALL(
1080    RETVAL = astPermMap(nin, cinperm, nout, coutperm, cconstant, options );
1081   )
1082   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1083  OUTPUT:
1084   RETVAL
1085 
1086 MODULE = Starlink::AST   PACKAGE = Starlink::AST::PolyMap
1087 
1088 AstPolyMap *
1089 new( class )
1090  CODE:
1091 #ifndef HASPOLYMAP
1092    Perl_croak(aTHX_ "PolyMap: Please upgrade to AST V3.x or greater");
1093 #else
1094   Perl_croak(aTHX_ "PolyMap not yet implemented");
1095 #endif
1096 
1097 MODULE = Starlink::AST   PACKAGE = Starlink::AST::ShiftMap
1098 
1099 AstShiftMap *
1100 new( class, shift, options )
1101   char * class
1102   AV* shift
1103   char * options
1104  PREINIT:
1105   int ncoord;
1106   double * cshift;
1107  CODE:
1108 #ifndef HASSHIFTMAP
1109    Perl_croak(aTHX_ "ShiftMap: Please upgrade to AST V3.x or greater");
1110 #else
1111   ncoord = av_len( shift ) + 1;
1112   cshift = pack1D(newRV_noinc((SV*)shift), 'd');
1113   ASTCALL(
1114    RETVAL = astShiftMap( ncoord, cshift, options);
1115   )
1116   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1117 #endif
1118  OUTPUT:
1119   RETVAL
1120 
1121 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SkyFrame
1122 
1123 AstSkyFrame *
1124 new( class, options )
1125   char * class
1126   char * options
1127  CODE:
1128   ASTCALL(
1129    RETVAL = astSkyFrame( options );
1130   )
1131   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1132  OUTPUT:
1133   RETVAL
1134 
1135 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SpecFrame
1136 
1137 AstSpecFrame *
1138 new( class, options )
1139   char * class
1140   char * options
1141  CODE:
1142 #ifndef HASSPECFRAME
1143    Perl_croak(aTHX_ "SpecFrame: Please upgrade to AST V2.x or greater");
1144 #else
1145   ASTCALL(
1146    RETVAL = astSpecFrame( options );
1147   )
1148   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1149 #endif
1150  OUTPUT:
1151   RETVAL
1152 
1153 MODULE = Starlink::AST   PACKAGE = Starlink::AST::DSBSpecFrame
1154 
1155 AstDSBSpecFrame *
1156 new( class, options )
1157   char * class
1158   char * options
1159  CODE:
1160 #ifndef HASDSBSPECFRAME
1161    Perl_croak(aTHX_ "DSBSpecFrame: Please upgrade to AST V3.4 or greater");
1162 #else
1163   ASTCALL(
1164    RETVAL = astDSBSpecFrame( options );
1165   )
1166   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1167 #endif
1168  OUTPUT:
1169   RETVAL
1170 
1171 MODULE = Starlink::AST   PACKAGE = Starlink::AST::TimeFrame
1172 
1173 AstTimeFrame *
1174 new( class, options )
1175   char * class
1176   char * options
1177  CODE:
1178 #ifndef HASTIMEFRAME
1179    Perl_croak(aTHX_ "TimeFrame: Please upgrade to AST V3.7 or greater");
1180 #else
1181   ASTCALL(
1182    RETVAL = astTimeFrame( options );
1183   )
1184   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1185 #endif
1186  OUTPUT:
1187   RETVAL
1188 
1189 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SlaMap
1190 
1191 AstSlaMap *
1192 new( class, flags, options )
1193   char * class
1194   int flags
1195   char * options
1196  CODE:
1197   ASTCALL(
1198    RETVAL = astSlaMap( flags, options );
1199   )
1200   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1201  OUTPUT:
1202   RETVAL
1203 
1204 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SphMap
1205 
1206 AstSphMap *
1207 new( class, options )
1208   char * class
1209   char * options
1210  CODE:
1211   ASTCALL(
1212    RETVAL = astSphMap( options );
1213   )
1214   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1215  OUTPUT:
1216   RETVAL
1217 
1218 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SpecMap
1219 
1220 AstSpecMap *
1221 new( class, nin, flags, options )
1222   char * class
1223   int nin
1224   int flags
1225   char * options
1226  CODE:
1227 #ifndef HASSPECMAP
1228    Perl_croak(aTHX_ "SpecMap: Please upgrade to AST V2.x or greater");
1229 #else
1230   ASTCALL(
1231    RETVAL = astSpecMap( nin, flags, options );
1232   )
1233   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1234 #endif
1235  OUTPUT:
1236   RETVAL
1237 
1238 MODULE = Starlink::AST   PACKAGE = Starlink::AST::TimeMap
1239 
1240 AstTimeMap *
1241 new( flags, options )
1242   int flags
1243   char * options
1244  CODE:
1245 #ifndef HASTIMEMAP
1246    Perl_croak(aTHX_ "TimeMap: Please upgrade to AST V3.7 or greater");
1247 #else
1248   ASTCALL(
1249    RETVAL = astTimeMap( flags, options );
1250   )
1251   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1252 #endif
1253  OUTPUT:
1254   RETVAL
1255 
1256 MODULE = Starlink::AST   PACKAGE = Starlink::AST::TranMap
1257 
1258 AstTranMap *
1259 new( class, map1, map2, options )
1260   char * class
1261   AstMapping * map1
1262   AstMapping * map2
1263   char * options
1264  CODE:
1265 #ifndef HASTRANMAP
1266    Perl_croak(aTHX_ "TranMap: Please upgrade to AST V3.2 or greater");
1267 #else
1268   ASTCALL(
1269    RETVAL = astTranMap( map1, map2, options );
1270   )
1271   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1272 #endif
1273  OUTPUT:
1274   RETVAL
1275 
1276 MODULE = Starlink::AST   PACKAGE = Starlink::AST::UnitMap
1277 
1278 AstUnitMap *
1279 new( class, ncoord, options )
1280   char * class
1281   int ncoord
1282   char * options
1283  CODE:
1284   ASTCALL(
1285    RETVAL = astUnitMap( ncoord, options );
1286   )
1287   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1288  OUTPUT:
1289   RETVAL
1290 
1291 MODULE = Starlink::AST   PACKAGE = Starlink::AST::WcsMap
1292 
1293 AstWcsMap *
1294 new( class, ncoord, type, lonax, latax, options )
1295   char * class
1296   int ncoord
1297   WcsMapType type
1298   int lonax
1299   int latax
1300   char * options
1301  CODE:
1302   ASTCALL(
1303    RETVAL = astWcsMap( ncoord, type, lonax, latax,options );
1304   )
1305   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1306  OUTPUT:
1307   RETVAL
1308 
1309 MODULE = Starlink::AST   PACKAGE = Starlink::AST::WinMap
1310 
1311 # we derive ncoord from the input array dimensions
1312 
1313 AstWinMap *
1314 new( class, ina, inb, outa, outb, options )
1315   char * class
1316   AV* ina
1317   AV* inb
1318   AV* outa
1319   AV* outb
1320   char * options
1321  CODE:
1322   /* minimal arg checking - lazy XXXX */
1323   RETVAL = astWinMap( av_len(ina)+1, pack1D(newRV_noinc((SV*)ina),'d'),
1324                       pack1D(newRV_noinc((SV*)inb),'d'),
1325                       pack1D(newRV_noinc((SV*)outa),'d'),
1326                       pack1D(newRV_noinc((SV*)outb),'d'),options );
1327   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1328  OUTPUT:
1329   RETVAL
1330 
1331 MODULE = Starlink::AST   PACKAGE = Starlink::AST::ZoomMap
1332 
1333 AstZoomMap *
1334 new( class, ncoord, zoom, options )
1335   char * class
1336   int ncoord
1337   double zoom
1338   char * options
1339  CODE:
1340   ASTCALL(
1341    RETVAL = astZoomMap( ncoord, zoom, options );
1342   )
1343   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1344  OUTPUT:
1345   RETVAL
1346 
1347 
1348 MODULE = Starlink::AST   PACKAGE = Starlink::AST PREFIX = ast
1349 
1350 void
1351 astClear( this, attrib )
1352   AstObject * this
1353   char * attrib
1354  CODE:
1355   ASTCALL(
1356     astClear( this, attrib );
1357   )
1358 
1359 # Store flag in the object when annulled so that the object destructor
1360 # does not cause a second annul.
1361 
1362 void
1363 astAnnul( this )
1364   AstObject * this
1365  PREINIT:
1366   SV* arg = ST(0);
1367  CODE:
1368   ASTCALL(
1369    this = astAnnul( this );
1370   )
1371   setPerlObjectAttr( arg, "_annul",newSViv(1));
1372 
1373 
1374 AstObject *
1375 ast_Clone( this )
1376   AstObject * this
1377  CODE:
1378   ASTCALL(
1379    RETVAL = astClone( this );
1380   )
1381   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1382  OUTPUT:
1383   RETVAL
1384 
1385 AstObject *
1386 ast_Copy( this )
1387   AstObject * this
1388  CODE:
1389   ASTCALL(
1390    RETVAL = astCopy( this );
1391   )
1392   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1393  OUTPUT:
1394   RETVAL
1395 
1396 # Note that we do not return a NULL object
1397 
1398 void
1399 astDelete( this )
1400   AstObject * this
1401  CODE:
1402   ASTCALL(
1403    this = astDelete( this );
1404   )
1405 
1406 void
1407 astExempt( this )
1408   AstObject * this
1409  CODE:
1410   ASTCALL(
1411    astExempt( this );
1412   )
1413 
1414 void
1415 astExport( this )
1416   AstObject * this
1417  CODE:
1418   ASTCALL(
1419    astExport( this );
1420   )
1421 
1422 int
1423 astHasAttribute( this, attrib )
1424   AstObject * this
1425   char * attrib
1426  CODE:
1427 #ifndef HASHASATTRIBUTE
1428    Perl_croak(aTHX_ "astHasAttribute: Please upgrade to AST V5.3 or newer");
1429 #else
1430   ASTCALL(
1431    RETVAL = astHasAttribute( this, attrib );
1432   )
1433 #endif
1434  OUTPUT:
1435   RETVAL
1436 
1437 const char *
1438 astGetC( this, attrib )
1439   AstObject * this
1440   char * attrib
1441  PREINIT:
1442   SV * arg = ST(0);
1443  CODE:
1444   if (astIsAPlot(this)) {
1445      PLOTCALL( arg,
1446         RETVAL = astGetC( this, attrib );
1447      )
1448   } else {
1449     ASTCALL(
1450      RETVAL = astGetC( this, attrib );
1451     )
1452   }
1453  OUTPUT:
1454   RETVAL
1455 
1456 # Float is just an alias for double
1457 
1458 double
1459 astGetD( this, attrib )
1460   AstObject * this
1461   char * attrib
1462  ALIAS:
1463   astGetF = 1
1464  PREINIT:
1465   SV * arg = ST(0);
1466  CODE:
1467   if (astIsAPlot(this)) {
1468      PLOTCALL( arg,
1469         RETVAL = astGetD( this, attrib );
1470      )
1471   } else {
1472     ASTCALL(
1473      RETVAL = astGetD( this, attrib );
1474     )
1475   }
1476  OUTPUT:
1477   RETVAL
1478 
1479 int
1480 astGetI( this, attrib )
1481   AstObject * this
1482   char * attrib
1483  ALIAS:
1484   astGetL = 1
1485  PREINIT:
1486   SV * arg = ST(0);
1487  CODE:
1488   if (astIsAPlot(this)) {
1489      PLOTCALL( arg,
1490         RETVAL = astGetI( this, attrib );
1491      )
1492   } else {
1493     ASTCALL(
1494      RETVAL = astGetI( this, attrib );
1495     )
1496   }
1497  OUTPUT:
1498   RETVAL
1499 
1500 # Need to decide later whether the astIsA functions need to be
1501 # implemented since Perl can do that - XXXX
1502 
1503 
1504 
1505 # sprintf behaviour is left to the enclosing perl layer
1506 
1507 void
1508 ast_Set(this, settings )
1509   AstObject * this
1510   char * settings
1511  CODE:
1512   ASTCALL(
1513    astSet(this, settings );
1514   )
1515 
1516 void
1517 astSetC( this, attrib, value )
1518   AstObject * this
1519   char * attrib
1520   char * value
1521  CODE:
1522   ASTCALL(
1523    astSetC( this, attrib, value );
1524   )
1525 
1526 # Float is just an alias for double
1527 
1528 void
1529 astSetD( this, attrib, value )
1530   AstObject * this
1531   char * attrib
1532   double value
1533  ALIAS:
1534   astSetF = 1
1535  CODE:
1536   ASTCALL(
1537    astSetD( this, attrib, value );
1538   )
1539 
1540 
1541 void
1542 astSetI( this, attrib, value )
1543   AstObject * this
1544   char * attrib
1545   int value
1546  ALIAS:
1547   astSetL = 1
1548  CODE:
1549   ASTCALL(
1550    astSetI( this, attrib, value );
1551   )
1552 
1553 void
1554 astShow( this )
1555   AstObject * this
1556  CODE:
1557   ASTCALL(
1558    astShow( this );
1559   )
1560 
1561 bool
1562 astTest( this, attrib )
1563   AstObject * this
1564   char * attrib
1565  CODE:
1566   ASTCALL(
1567    RETVAL = astTest( this, attrib );
1568   )
1569  OUTPUT:
1570   RETVAL
1571 
1572 # Use annul as automatic destructor
1573 # For automatic destructor we do not want to throw an exception
1574 # on error. So do not use ASTCALL. Do a manual printf to stderr and continue.
1575 # Does nothing if a key _annul is present in the object and is true.
1576 # This condition is usually met if the user has manually called the Annull
1577 # method on the object.
1578 
1579 void
1580 astDESTROY( obj )
1581   SV * obj
1582  PREINIT:
1583   int my_xsstatus_val = 0;
1584   int *my_xsstatus = &my_xsstatus_val;
1585   int *old_ast_status;
1586   int i;
1587   SV ** elem;
1588   SV * flag;
1589   char one[3] = "! ";
1590   char two[3] = "!!";
1591   char * pling;
1592   AV* local_err;
1593   char * s = CopFILE( PL_curcop );
1594   STRLEN msglen;
1595   IV mytmp;
1596   AstObject * this;
1597  CODE:
1598   /* see if we have annulled already */
1599   flag = getPerlObjectAttr( obj, "_annul");
1600   if (flag == NULL || ! SvTRUE(flag) ) {
1601     /* DESTROY always seems to insert stub code for SVREF not what is in  */
1602     /* the typemap file. Do it manually */
1603     mytmp = extractAstIntPointer( obj );
1604     this = INT2PTR( AstObject *, mytmp );
1605 
1606     MUTEX_LOCK(&AST_mutex);
1607     My_astClearErrMsg();
1608     old_ast_status = astWatch( my_xsstatus );
1609     this = astAnnul( this );
1610     astWatch( old_ast_status );
1611     My_astCopyErrMsg( &local_err, *my_xsstatus );
1612     MUTEX_UNLOCK(&AST_mutex);
1613     if (*my_xsstatus != 0 ) {
1614       for (i=0; i <= av_len( local_err ); i++ ) {
1615         pling = ( i == 0 ? two : one );
1616         elem = av_fetch( local_err, i, 0 );
1617         if (elem != NULL ) {
1618           PerlIO_printf( PerlIO_stderr(),  "%s %s\n", pling,
1619 		         SvPV( *elem, msglen ));
1620         }
1621       }
1622       if (!s) s = "(none)";
1623       PerlIO_printf( PerlIO_stderr(),
1624                      "!  (in cleanup from file %s:%" IVdf ")\n",
1625                      s, (IV) CopLINE(PL_curcop));
1626     }
1627   }
1628 
1629 MODULE = Starlink::AST   PACKAGE = Starlink::AST::KeyMap
1630 
1631 int
1632 AST__BADTYPE()
1633  CODE:
1634 #ifdef AST__BADTYPE
1635     RETVAL = AST__BADTYPE;
1636 #else
1637     Perl_croak(aTHX_ "Constant AST__BADTYPE not defined\n");
1638 #endif
1639  OUTPUT:
1640   RETVAL
1641 
1642 int
1643 AST__INTTYPE()
1644  CODE:
1645 #ifdef AST__INTTYPE
1646     RETVAL = AST__INTTYPE;
1647 #else
1648     Perl_croak(aTHX_ "Constant AST__INTTYPE not defined\n");
1649 #endif
1650  OUTPUT:
1651   RETVAL
1652 
1653 int
1654 AST__SINTTYPE()
1655  CODE:
1656 #ifdef AST__SINTTYPE
1657     RETVAL = AST__SINTTYPE;
1658 #else
1659     Perl_croak(aTHX_ "Constant AST__SINTTYPE not defined\n");
1660 #endif
1661  OUTPUT:
1662   RETVAL
1663 
1664 int
1665 AST__DOUBLETYPE()
1666  CODE:
1667 #ifdef AST__DOUBLETYPE
1668     RETVAL = AST__DOUBLETYPE;
1669 #else
1670     Perl_croak(aTHX_ "Constant AST__DOUBLETYPE not defined\n");
1671 #endif
1672  OUTPUT:
1673   RETVAL
1674 
1675 int
1676 AST__FLOATTYPE()
1677  CODE:
1678 #ifdef AST__FLOATTYPE
1679     RETVAL = AST__DOUBLETYPE;
1680 #else
1681     Perl_croak(aTHX_ "Constant AST__FLOATTYPE not defined\n");
1682 #endif
1683  OUTPUT:
1684   RETVAL
1685 
1686 int
1687 AST__STRINGTYPE()
1688  CODE:
1689 #ifdef AST__STRINGTYPE
1690     RETVAL = AST__STRINGTYPE;
1691 #else
1692     Perl_croak(aTHX_ "Constant AST__STRINGTYPE not defined\n");
1693 #endif
1694  OUTPUT:
1695   RETVAL
1696 
1697 int
1698 AST__OBJECTTYPE()
1699  CODE:
1700 #ifdef AST__OBJECTTYPE
1701     RETVAL = AST__OBJECTTYPE;
1702 #else
1703     Perl_croak(aTHX_ "Constant AST__OBJECTTYPE not defined\n");
1704 #endif
1705  OUTPUT:
1706   RETVAL
1707 
1708 int
1709 AST__UNDEFTYPE()
1710  CODE:
1711 #ifdef AST__UNDEFTYPE
1712     RETVAL = AST__UNDEFTYPE;
1713 #else
1714     Perl_croak(aTHX_ "Constant AST__UNDEFTYPE not defined\n");
1715 #endif
1716  OUTPUT:
1717   RETVAL
1718 
1719 MODULE = Starlink::AST   PACKAGE = Starlink::AST::KeyMap PREFIX = ast
1720 
1721 AstKeyMap *
1722 new( class, options )
1723   char * class
1724   char * options
1725  CODE:
1726 #ifndef HASKEYMAP
1727   Perl_croak(aTHX_ "AstKeyMap: Please upgrade to AST V3.5 or newer");
1728 #else
1729   ASTCALL(
1730    RETVAL = astKeyMap( options );
1731   )
1732   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
1733 #endif
1734  OUTPUT:
1735   RETVAL
1736 
1737 void
1738 astMapPutU( this, key, comment )
1739   AstKeyMap * this
1740   char * key
1741   char * comment
1742  CODE:
1743 #ifndef HASMAPPUTU
1744   Perl_croak(aTHX_ "astMapPutU: Please upgrade to AST V5.3 or newer");
1745 #else
1746   ASTCALL(
1747    astMapPutU( this, key, comment);
1748   )
1749 #endif
1750 
1751 void
1752 astMapPut0D( this, key, value, comment)
1753   AstKeyMap * this
1754   char * key
1755   double value
1756   char * comment
1757  CODE:
1758 #ifndef HASKEYMAP
1759   Perl_croak(aTHX_ "astMapPut0D: Please upgrade to AST V3.5 or newer");
1760 #else
1761   ASTCALL(
1762    astMapPut0D( this, key, value, comment);
1763   )
1764 #endif
1765 
1766 void
1767 astMapPut0I( this, key, value, comment)
1768   AstKeyMap * this
1769   char * key
1770   int value
1771   char * comment
1772  CODE:
1773 #ifndef HASKEYMAP
1774   Perl_croak(aTHX_ "astMapPut0I: Please upgrade to AST V3.5 or newer");
1775 #else
1776   ASTCALL(
1777    astMapPut0I( this, key, value, comment);
1778   )
1779 #endif
1780 
1781 void
1782 astMapPut0S( this, key, value, comment)
1783   AstKeyMap * this
1784   char * key
1785   int value
1786   char * comment
1787  CODE:
1788 #ifndef HASKEYMAPSHORT
1789   Perl_croak(aTHX_ "astMapPut0S: Please upgrade to AST V5.4 or newer");
1790 #else
1791   if ( value < SHRT_MIN || value > SHRT_MAX ) {
1792     Perl_croak( aTHX_ "astMapPut0S: Supplied short value (%d) is out of range",
1793                 value );
1794   }
1795   ASTCALL(
1796    astMapPut0S( this, key, value, comment);
1797   )
1798 #endif
1799 
1800 void
1801 astMapPut0C( this, key, value, comment)
1802   AstKeyMap * this
1803   char * key
1804   char * value
1805   char * comment
1806  CODE:
1807 #ifndef HASKEYMAP
1808   Perl_croak(aTHX_ "astMapPut0C: Please upgrade to AST V3.5 or newer");
1809 #else
1810   ASTCALL(
1811    astMapPut0C( this, key, value, comment);
1812   )
1813 #endif
1814 
1815 void
1816 astMapPut0A( this, key, value, comment)
1817   AstKeyMap * this
1818   char * key
1819   AstObject * value
1820   char * comment
1821  CODE:
1822 #ifndef HASKEYMAP
1823   Perl_croak(aTHX_ "astMapPut0A: Please upgrade to AST V3.5 or newer");
1824 #else
1825   ASTCALL(
1826    astMapPut0A( this, key, value, comment);
1827   )
1828 #endif
1829 
1830 void
1831 astMapPut1D( this, key, values, comment)
1832   AstKeyMap * this
1833   char * key
1834   AV * values
1835   char * comment
1836  PREINIT:
1837   int size;
1838   double * val;
1839  CODE:
1840 #ifndef HASKEYMAP
1841   Perl_croak(aTHX_ "astMapPut1D: Please upgrade to AST V3.5 or newer");
1842 #else
1843   size = av_len(values) + 1;
1844   val = pack1D( newRV_noinc((SV*)values),'d');
1845   ASTCALL(
1846    astMapPut1D( this, key, size, val, comment);
1847   )
1848 #endif
1849 
1850 void
1851 astMapPut1I( this, key, values, comment)
1852   AstKeyMap * this
1853   char * key
1854   AV * values
1855   char * comment
1856  PREINIT:
1857   int size;
1858   int * val;
1859  CODE:
1860 #ifndef HASKEYMAP
1861   Perl_croak(aTHX_ "astMapPut1I: Please upgrade to AST V3.5 or newer");
1862 #else
1863   size = av_len(values) + 1;
1864   val = pack1D( newRV_noinc((SV*)values),'i');
1865   ASTCALL(
1866    astMapPut1I( this, key, size, val, comment);
1867   )
1868 #endif
1869 
1870 void
1871 astMapPut1S( this, key, values, comment)
1872   AstKeyMap * this
1873   char * key
1874   AV * values
1875   char * comment
1876  PREINIT:
1877   int size;
1878   int i;
1879   short * val;
1880  CODE:
1881 #ifndef HASKEYMAPSHORT
1882   Perl_croak(aTHX_ "astMapPut1S: Please upgrade to AST V5.4 or newer");
1883 #else
1884   size = av_len(values) + 1;
1885   for (i=0; i<size;i++) {
1886      SV ** element = av_fetch( values, i, 0 );
1887      if (element) {
1888         IV ival = 0;
1889         if (SvROK(*element)) {
1890           Perl_croak( aTHX_ "Can not store reference in short keymap" );
1891         }
1892         ival = SvIV(*element);
1893         if (ival < SHRT_MIN || ival > SHRT_MAX) {
1894           Perl_croak( aTHX_ "MapPut1S: Value of element %d (%ld) is out of range for a short",
1895                       i, (long)ival );
1896         }
1897      }
1898   }
1899   val = pack1D( newRV_noinc((SV*)values),'s');
1900   ASTCALL(
1901    astMapPut1S( this, key, size, val, comment);
1902   )
1903 #endif
1904 
1905 void
1906 astMapPut1C( this, key, values, comment)
1907   AstKeyMap * this
1908   char * key
1909   AV * values
1910   char * comment
1911  PREINIT:
1912   int size;
1913   char ** val;
1914  CODE:
1915 #ifndef HASKEYMAP
1916   Perl_croak(aTHX_ "astMapPut1C: Please upgrade to AST V3.5 or newer");
1917 #else
1918   size = av_len(values) + 1;
1919   val = pack1Dchar( values );
1920   ASTCALL(
1921    astMapPut1C( this, key, size, (const char **)val, comment);
1922   )
1923 #endif
1924 
1925 void
1926 astMapPut1A( this, key, values, comment)
1927   AstKeyMap * this
1928   char * key
1929   AV * values
1930   char * comment
1931  PREINIT:
1932   int size;
1933   AstObject ** val;
1934  CODE:
1935 #ifndef HASKEYMAP
1936   Perl_croak(aTHX_ "astMapPut1A: Please upgrade to AST V3.5 or newer");
1937 #else
1938   size = av_len(values) + 1;
1939   val = pack1DAstObj( values );
1940   ASTCALL(
1941    astMapPut1A( this, key, size, val, comment);
1942   )
1943 #endif
1944 
1945 void
1946 astMapGet0D( this, key )
1947   AstKeyMap * this
1948   char * key
1949  PREINIT:
1950   double RETVAL;
1951   int status;
1952  PPCODE:
1953 #ifndef HASKEYMAP
1954   Perl_croak(aTHX_ "astMapGet0D: Please upgrade to AST V3.5 or newer");
1955 #else
1956   ASTCALL(
1957     status = astMapGet0D( this, key, &RETVAL );
1958   )
1959   if (status != 0) {
1960     XPUSHs(sv_2mortal(newSVnv(RETVAL)));
1961   } else {
1962     XSRETURN_EMPTY;
1963   }
1964 #endif
1965 
1966 # Short ints are handled by "I" interface because Perl will always
1967 # convert the short to an IV.
1968 
1969 void
1970 astMapGet0I( this, key )
1971   AstKeyMap * this
1972   char * key
1973  PREINIT:
1974   int RETVAL;
1975   int status;
1976  ALIAS:
1977    MapGet0S = 1
1978  PPCODE:
1979 #ifndef HASKEYMAP
1980   Perl_croak(aTHX_ "astMapGet0I: Please upgrade to AST V3.5 or newer");
1981 #else
1982   ASTCALL(
1983     status = astMapGet0I( this, key, &RETVAL );
1984   )
1985   if (status != 0) {
1986     XPUSHs(sv_2mortal(newSViv(RETVAL)));
1987   } else {
1988     XSRETURN_EMPTY;
1989   }
1990 #endif
1991 
1992 void
1993 astMapGet0C( this, key )
1994   AstKeyMap * this
1995   char * key
1996  PREINIT:
1997   char * RETVAL;
1998   int status;
1999  PPCODE:
2000 #ifndef HASKEYMAP
2001   Perl_croak(aTHX_ "astMapGet0C: Please upgrade to AST V3.5 or newer");
2002 #else
2003   ASTCALL(
2004     status = astMapGet0C( this, key, (const char **)&RETVAL );
2005   )
2006   if (status != 0) {
2007     XPUSHs(sv_2mortal(newSVpvn(RETVAL,strlen(RETVAL))));
2008   } else {
2009     XSRETURN_EMPTY;
2010   }
2011 #endif
2012 
2013 # Note the underscore in the name because currently we return
2014 # a Starlink::AST object rather than a real object and there is
2015 # a perl layer to rebless. We should probably do this in the C
2016 # layer
2017 
2018 void
2019 ast_MapGet0A( this, key )
2020   AstKeyMap * this
2021   char * key
2022  PREINIT:
2023   AstObject * RETVAL;
2024   int status;
2025   SV * sv;
2026  PPCODE:
2027 #ifndef HASKEYMAP
2028   Perl_croak(aTHX_ "astMapGet0A: Please upgrade to AST V3.5 or newer");
2029 #else
2030   ASTCALL(
2031     status = astMapGet0A( this, key, &RETVAL );
2032   )
2033   if (status != 0) {
2034     /* Have an AstObject pointer. Convert to object. */
2035     sv = createPerlObject( "AstObjectPtr", RETVAL );
2036     XPUSHs(sv_2mortal( sv ));
2037   } else {
2038     XSRETURN_EMPTY;
2039   }
2040 #endif
2041 
2042 
2043 void
2044 astMapGet1D( this, key )
2045   AstKeyMap * this
2046   char * key
2047  PREINIT:
2048   int i;
2049   int status;
2050   double * outarr;
2051   int nelems;
2052  PPCODE:
2053 #ifndef HASKEYMAP
2054   Perl_croak(aTHX_ "astMapGet1D: Please upgrade to AST V3.5 or newer");
2055 #else
2056   /* First we need to find out how many elements are in the KeyMap */
2057   nelems = astMapLength( this, key );
2058   if (nelems == 0) {
2059     XSRETURN_EMPTY;
2060   }
2061 
2062   /* get some memory */
2063   outarr = get_mortalspace( nelems, 'd' );
2064 
2065   ASTCALL(
2066     status = astMapGet1D( this, key, nelems, &nelems, outarr );
2067   )
2068   if (status != 0) {
2069     for (i=0; i < nelems; i++) {
2070       XPUSHs(sv_2mortal(newSVnv( outarr[i] )));
2071     }
2072   } else {
2073     XSRETURN_EMPTY;
2074   }
2075 #endif
2076 
2077 # The short int version does not need a separate implementation
2078 # because perl doesn't care and will end up reading it in as an IV
2079 # anyhow. The only reason to implement the "S" routine separately
2080 # is for the smaller memory requirement.
2081 
2082 void
2083 astMapGet1I( this, key )
2084   AstKeyMap * this
2085   char * key
2086  PREINIT:
2087   int i;
2088   int status;
2089   int * outarr;
2090   int nelems;
2091  ALIAS:
2092   MapGet1S = 1
2093  PPCODE:
2094 #ifndef HASKEYMAP
2095   Perl_croak(aTHX_ "astMapGet1I: Please upgrade to AST V3.5 or newer");
2096 #else
2097   /* First we need to find out how many elements are in the KeyMap */
2098   nelems = astMapLength( this, key );
2099   if (nelems == 0) {
2100     XSRETURN_EMPTY;
2101   }
2102 
2103   /* get some memory */
2104   outarr = get_mortalspace( nelems, 'i' );
2105 
2106   ASTCALL(
2107     status = astMapGet1I( this, key, nelems, &nelems, outarr );
2108   )
2109   if (status != 0) {
2110     for (i=0; i < nelems; i++) {
2111       XPUSHs(sv_2mortal(newSViv( outarr[i] )));
2112     }
2113   } else {
2114     XSRETURN_EMPTY;
2115   }
2116 #endif
2117 
2118 void
2119 ast_MapGet1A( this, key )
2120   AstKeyMap * this
2121   char * key
2122  PREINIT:
2123   SV * sv;
2124   int i;
2125   int status;
2126   AstObject ** outarr;
2127   int nelems;
2128  PPCODE:
2129 #ifndef HASKEYMAP
2130   Perl_croak(aTHX_ "astMapGet1A: Please upgrade to AST V3.5 or newer");
2131 #else
2132   /* First we need to find out how many elements are in the KeyMap */
2133   nelems = astMapLength( this, key );
2134   if (nelems == 0) {
2135     XSRETURN_EMPTY;
2136   }
2137 
2138   /* get some memory */
2139   outarr = get_mortalspace( nelems, 'v' );
2140 
2141   ASTCALL(
2142     status = astMapGet1A( this, key, nelems, &nelems, outarr );
2143   )
2144   if (status != 0) {
2145     for (i=0; i < nelems; i++) {
2146       /* Have an AstObject pointer. Convert to object. */
2147       sv = createPerlObject( "AstObjectPtr", outarr[i] );
2148       XPUSHs(sv_2mortal( sv ));
2149     }
2150   } else {
2151     XSRETURN_EMPTY;
2152   }
2153 #endif
2154 
2155 void
2156 astMapGet1C( this, key )
2157   AstKeyMap * this
2158   char * key
2159  PREINIT:
2160   SV * sv;
2161   int i;
2162   int status;
2163   char * buffer;
2164   char * tmpp;
2165   int nelems;
2166   int maxlen = 80; /* max length of each string in map. Includes NUL */
2167  PPCODE:
2168 #ifndef HASKEYMAP
2169   Perl_croak(aTHX_ "astMapGet1C: Please upgrade to AST V3.5 or newer");
2170 #else
2171   /* First we need to find out how many elements are in the KeyMap */
2172   nelems = astMapLength( this, key );
2173   if (nelems == 0) {
2174     XSRETURN_EMPTY;
2175   }
2176 
2177   /* get some memory */
2178   buffer = get_mortalspace( nelems * maxlen, 'u' );
2179 
2180   ASTCALL(
2181     status = astMapGet1C( this, key, maxlen, nelems, &nelems, buffer );
2182   )
2183   if (status != 0) {
2184     /* set temp pointer to start of buffer */
2185     tmpp = buffer;
2186     for (i=0; i < nelems; i++) {
2187       /* Jump through the buffer in maxlen hops */
2188       XPUSHs(sv_2mortal( newSVpvn(tmpp, strlen(tmpp)) ));
2189       tmpp += maxlen;
2190     }
2191   } else {
2192     XSRETURN_EMPTY;
2193   }
2194 #endif
2195 
2196 void
2197 astMapRemove( this, key )
2198   AstKeyMap * this
2199   char * key
2200  CODE:
2201 #ifndef HASKEYMAP
2202   Perl_croak(aTHX_ "astMapRemove: Please upgrade to AST V3.5 or newer");
2203 #else
2204 
2205   ASTCALL(
2206     astMapRemove( this, key );
2207   )
2208 #endif
2209 
2210 int
2211 astMapSize( this )
2212   AstKeyMap * this
2213  CODE:
2214 #ifndef HASKEYMAP
2215   Perl_croak(aTHX_ "astMapSize: Please upgrade to AST V3.5 or newer");
2216 #else
2217   ASTCALL(
2218    RETVAL = astMapSize( this );
2219   )
2220 #endif
2221  OUTPUT:
2222   RETVAL
2223 
2224 int
2225 astMapLength( this, key )
2226   AstKeyMap * this
2227   char * key
2228  CODE:
2229 #ifndef HASKEYMAP
2230   Perl_croak(aTHX_ "astMapLength: Please upgrade to AST V3.5 or newer");
2231 #else
2232   ASTCALL(
2233    RETVAL = astMapLength( this, key );
2234   )
2235 #endif
2236  OUTPUT:
2237   RETVAL
2238 
2239 bool
2240 astMapHasKey( this, key )
2241   AstKeyMap * this
2242   char * key
2243  PREINIT:
2244   int haskey;
2245  CODE:
2246 #ifndef HASKEYMAP
2247   Perl_croak(aTHX_ "astMapHasKey: Please upgrade to AST V3.5 or newer");
2248 #else
2249   ASTCALL(
2250     haskey = astMapHasKey( this, key );
2251   )
2252   RETVAL = ( haskey == 0 ? 0 : 1 );
2253 #endif
2254  OUTPUT:
2255   RETVAL
2256 
2257 const char *
2258 astMapKey( this, index )
2259   AstKeyMap * this
2260   int index
2261  CODE:
2262 #ifndef HASKEYMAP
2263   Perl_croak(aTHX_ "astMapKey: Please upgrade to AST V3.5 or newer");
2264 #else
2265   ASTCALL(
2266     RETVAL = astMapKey( this, index );
2267   )
2268 #endif
2269  OUTPUT:
2270   RETVAL
2271 
2272 int
2273 astMapType( this, key )
2274   AstKeyMap * this
2275   char * key
2276  CODE:
2277 #ifndef HASKEYMAP
2278   Perl_croak(aTHX_ "astMapType: Please upgrade to AST V3.5 or newer");
2279 #else
2280   ASTCALL(
2281    RETVAL = astMapType( this, key );
2282   )
2283 #endif
2284  OUTPUT:
2285   RETVAL
2286 
2287 bool
2288 astMapDefined( this, key )
2289   AstKeyMap * this
2290   char * key
2291  CODE:
2292 #ifndef HASMAPDEFINED
2293   Perl_croak(aTHX_ "astMapDefined: Please upgrade to AST V7.2 or newer");
2294 #else
2295   ASTCALL(
2296    RETVAL = astMapDefined( this, key );
2297   )
2298 #endif
2299  OUTPUT:
2300   RETVAL
2301 
2302 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Frame PREFIX = ast
2303 
2304 
2305 double
2306 astAngle( this, a, b, c )
2307   AstFrame * this
2308   AV* a
2309   AV* b
2310   AV* c
2311  PREINIT:
2312   double * aa;
2313   double * bb;
2314   double * cc;
2315   int naxes;
2316  CODE:
2317   /* Create C arrays of the correct dimensions */
2318   naxes = astGetI( this, "Naxes" );
2319 
2320   /* Copy from the perl array to the C array */
2321   if (av_len(a) != naxes-1)
2322      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2323                 naxes);
2324   if (av_len(b) != naxes-1)
2325      Perl_croak(aTHX_ "Number of elements in second coord array must be %d",
2326                 naxes);
2327   if (av_len(c) != naxes-1)
2328      Perl_croak(aTHX_ "Number of elements in third coord array must be %d",
2329                 naxes);
2330 
2331   aa = pack1D( newRV_noinc((SV*)a), 'd');
2332   bb = pack1D( newRV_noinc((SV*)b), 'd');
2333   cc = pack1D( newRV_noinc((SV*)c), 'd');
2334 
2335   /* Call the ast function */
2336   ASTCALL(
2337    RETVAL = astAngle( this, aa, bb, cc);
2338   )
2339  OUTPUT:
2340   RETVAL
2341 
2342 double
2343 astAxAngle( this, a, b, axis )
2344   AstFrame * this
2345   AV* a
2346   AV* b
2347   int axis
2348  PREINIT:
2349   double * aa;
2350   double * bb;
2351   int naxes;
2352  CODE:
2353   /* Create C arrays of the correct dimensions */
2354   naxes = astGetI( this, "Naxes" );
2355 
2356   /* Copy from the perl array to the C array */
2357   if (av_len(a) != naxes-1)
2358      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2359                 naxes);
2360   if (av_len(b) != naxes-1)
2361      Perl_croak(aTHX_ "Number of elements in second coord array must be %d",
2362                 naxes);
2363 
2364   aa = pack1D( newRV_noinc((SV*)a), 'd');
2365   bb = pack1D( newRV_noinc((SV*)b), 'd');
2366   ASTCALL(
2367    RETVAL = astAxAngle( this, aa, bb, axis);
2368   )
2369  OUTPUT:
2370   RETVAL
2371 
2372 double
2373 astAxDistance( this, axis, v1, v2)
2374   AstFrame * this
2375   int axis
2376   double v1
2377   double v2
2378  CODE:
2379   ASTCALL(
2380    RETVAL = astAxDistance( this, axis, v1, v2);
2381   )
2382  OUTPUT:
2383   RETVAL
2384 
2385 double
2386 astAxOffset( this, axis, v1, dist)
2387   AstFrame * this
2388   int axis
2389   double v1
2390   double dist
2391  CODE:
2392   ASTCALL(
2393    RETVAL = astAxOffset( this, axis, v1, dist);
2394   )
2395  OUTPUT:
2396   RETVAL
2397 
2398 AstFrameSet *
2399 astConvert( from, to, domainlist )
2400   AstFrame * from
2401   AstFrame * to
2402   char * domainlist
2403  CODE:
2404   ASTCALL(
2405    RETVAL = astConvert( from, to, domainlist );
2406   )
2407   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
2408  OUTPUT:
2409   RETVAL
2410 
2411 double
2412 astDistance( this, point1, point2 )
2413   AstFrame * this
2414   AV* point1
2415   AV* point2
2416  PREINIT:
2417   double * aa;
2418   double * bb;
2419   int naxes;
2420  CODE:
2421   /* Create C arrays of the correct dimensions */
2422   naxes = astGetI( this, "Naxes" );
2423 
2424   /* Copy from the perl array to the C array */
2425   if (av_len(point1) != naxes-1)
2426      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2427                 naxes);
2428   if (av_len(point2) != naxes-1)
2429      Perl_croak(aTHX_ "Number of elements in second coord array must be %d",
2430                 naxes);
2431 
2432   aa = pack1D( newRV_noinc((SV*)point1), 'd');
2433   bb = pack1D( newRV_noinc((SV*)point2), 'd');
2434   ASTCALL(
2435    RETVAL = astDistance( this, aa, bb);
2436   )
2437  OUTPUT:
2438   RETVAL
2439 
2440 AstFrameSet *
2441 astFindFrame( this, template, domainlist )
2442   AstFrame * this
2443   AstFrame * template
2444   char * domainlist
2445  CODE:
2446   ASTCALL(
2447    RETVAL = astFindFrame( this, template, domainlist );
2448   )
2449   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
2450  OUTPUT:
2451   RETVAL
2452 
2453 const char *
2454 astFormat( this, axis, value )
2455   AstFrame * this
2456   int axis
2457   double value
2458  CODE:
2459   ASTCALL(
2460    RETVAL = astFormat( this, axis, value );
2461   )
2462  OUTPUT:
2463   RETVAL
2464 
2465 int
2466 astGetActiveUnit( this )
2467   AstFrame * this
2468  CODE:
2469 #ifndef HASGETACTIVEUNIT
2470   Perl_croak(aTHX_ "astGetActiveUnit: Please upgrade to AST V2.x or newer");
2471 #else
2472   ASTCALL(
2473    RETVAL = astGetActiveUnit( this );
2474   )
2475 #endif
2476  OUTPUT:
2477   RETVAL
2478 
2479 # @normalised = $wcs->Norm( @unnormalised );
2480 
2481 void
2482 astNorm( this, ... )
2483   AstFrame * this
2484  PREINIT:
2485   int argoff = 1; /* number of fixed arguments */
2486   int naxes;
2487   double * aa;
2488   int i;
2489   int ncoord_in;
2490   double * inputs;
2491  PPCODE:
2492   /* Create C arrays of the correct dimensions */
2493   naxes = astGetI( this, "Naxes" );
2494   ncoord_in = items - argoff;
2495 
2496   /* Copy from the perl array to the C array */
2497   if (naxes != ncoord_in )
2498      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2499                 naxes);
2500   aa = get_mortalspace( ncoord_in, 'd' );
2501   for (i=0; i<ncoord_in; i++) {
2502      int argpos = i + argoff;
2503      aa[i] = SvNV( ST(argpos) );
2504   }
2505 
2506   ASTCALL(
2507    astNorm( this, aa );
2508   )
2509 
2510   for (i=0; i<naxes; i++) {
2511     XPUSHs( sv_2mortal( newSVnv( aa[i] ) ) );
2512   }
2513 
2514 # Return list
2515 
2516 void
2517 astOffset( this, point1, point2, offset )
2518   AstFrame * this
2519   AV* point1
2520   AV* point2
2521   double offset
2522  PREINIT:
2523   int naxes;
2524   double * aa;
2525   double * bb;
2526   double * point3;
2527   int i;
2528   AV * myoffset;
2529  PPCODE:
2530   naxes = astGetI( this, "Naxes" );
2531 
2532   /* Copy from the perl array to the C array */
2533   if (av_len(point1) != naxes-1)
2534      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2535                 naxes);
2536   aa = pack1D( newRV_noinc((SV*)point1), 'd');
2537   if (av_len(point2) != naxes-1)
2538      Perl_croak(aTHX_ "Number of elements in second coord array must be %d",
2539                 naxes);
2540   bb = pack1D( newRV_noinc((SV*)point2), 'd');
2541 
2542 
2543   /* Somewhere to put the return values */
2544   point3 = get_mortalspace( naxes, 'd' );
2545 
2546   ASTCALL(
2547    astOffset( this, aa, bb, offset, point3 );
2548   )
2549 
2550   /* now need to push the resulting values onto the return stack */
2551   /* Put everything in an array [rather than the stack] in order to
2552      be consistent in returning C arrays as perl arrays. */
2553   myoffset = newAV();
2554   for (i =0; i < naxes; i++ ) {
2555     av_push( myoffset, newSVnv( point3[i] ));
2556   }
2557   XPUSHs( newRV_noinc( (SV*)myoffset ));
2558 
2559 
2560 
2561 # Returns angle and reference to array of pair of coordinates
2562 
2563 void
2564 astOffset2( this, point1, angle, offset )
2565   AstFrame * this
2566   AV* point1
2567   double angle
2568   double offset
2569  PREINIT:
2570   int naxes;
2571   double * aa;
2572   double * point2;
2573   int i;
2574   double RETVAL;
2575   AV * myoffset;
2576  PPCODE:
2577   naxes = astGetI( this, "Naxes" );
2578 
2579   /* Copy from the perl array to the C array */
2580   if (av_len(point1) != naxes-1)
2581      Perl_croak(aTHX_ "Number of elements in first coord array must be %d",
2582                 naxes);
2583   aa = pack1D( newRV_noinc((SV*)point1), 'd');
2584 
2585   /* Somewhere to put the return values */
2586   point2 = get_mortalspace( naxes, 'd' );
2587 
2588   ASTCALL(
2589    RETVAL = astOffset2( this, aa, angle, offset, point2 );
2590   )
2591 
2592   /* Push the angle on to the stack */
2593   XPUSHs(sv_2mortal(newSVnv(RETVAL)));
2594 
2595   /* Put everything in an array [rather than the stack] in order to
2596      be consistent in returning C arrays as perl arrays. */
2597   myoffset = newAV();
2598   for (i =0; i < naxes; i++ ) {
2599     av_push( myoffset, newSVnv( point2[i] ));
2600   }
2601   XPUSHs( newRV_noinc( (SV*)myoffset ));
2602 
2603 
2604 void
2605 astPermAxes( this, perm )
2606   AstFrame * this
2607   AV* perm
2608  PREINIT:
2609   int * aa;
2610   int naxes;
2611  CODE:
2612   naxes = astGetI(this, "Naxes");
2613   /* Copy from the perl array to the C array */
2614   if (av_len(perm) != naxes-1)
2615      Perl_croak(aTHX_ "Number of elements in perm array must be %d",
2616                 naxes);
2617   aa = pack1D( newRV_noinc((SV*)perm), 'i');
2618   ASTCALL(
2619    astPermAxes( this, aa );
2620   )
2621 
2622 # Returns a new frame and an optional mapping
2623 # Also note that we count axes ourselves
2624 
2625 # We always ask for the return mapping and we always
2626 # return both the new frame and the mapping from the old
2627 # The perl side decides whether the user wants to keep the
2628 # mapping or not depending on context (Which is unavailable
2629 # to XS)
2630 
2631 void
2632 ast_PickAxes( this, axes )
2633   AstFrame * this;
2634   AV* axes
2635  PREINIT:
2636   int maxaxes;
2637   int naxes;
2638   int * aa;
2639   AstMapping * map;
2640   AstFrame * newframe;
2641  PPCODE:
2642   maxaxes = astGetI(this, "Naxes");
2643   naxes = av_len(axes) + 1;
2644   if ( naxes > maxaxes )
2645     Perl_croak(aTHX_ "Number of axes selected must be less than number of axes in frame");
2646   aa = pack1D( newRV_noinc((SV*)axes), 'i');
2647   ASTCALL(
2648    newframe = astPickAxes( this, naxes, aa, &map);
2649   )
2650   if ( newframe == AST__NULL ) XSRETURN_UNDEF;
2651   /* Create perl objects from the two return arguments */
2652   XPUSHs(sv_2mortal( createPerlObject( "AstFramePtr", (AstObject*)newframe )));
2653   XPUSHs(sv_2mortal( createPerlObject( "AstMappingPtr", (AstObject*)map )));
2654 
2655 
2656 # Returns reference to array [point4], plus two distances
2657 
2658 void
2659 astResolve( this, point1, point2, point3 )
2660   AstFrame * this
2661   AV* point1
2662   AV* point2
2663   AV* point3
2664  PREINIT:
2665   double * cpoint1;
2666   double * cpoint2;
2667   double * cpoint3;
2668   double * cpoint4;
2669   AV * point4;
2670   double d1;
2671   double d2;
2672   int len;
2673   int naxes;
2674  PPCODE:
2675   naxes = astGetI(this, "Naxes");
2676   len = av_len(point1) + 1;
2677   if ( naxes != len )
2678     Perl_croak(aTHX_ "Number of coords in point1 must be equal to the number of axes in frame [%d != %d]", naxes, len);
2679   len = av_len(point2) + 1;
2680   if ( naxes != len )
2681     Perl_croak(aTHX_ "Number of coords in point2 must be equal to the number of axes in frame [%d != %d]", naxes, len);
2682   len = av_len(point3) + 1;
2683   if ( naxes != len )
2684     Perl_croak(aTHX_ "Number of coords in point3 must be equal to the number of axes in frame [%d != %d]", naxes, len);
2685 
2686   cpoint1 = pack1D( newRV_noinc((SV*)point1), 'd');
2687   cpoint2 = pack1D( newRV_noinc((SV*)point2), 'd');
2688   cpoint3 = pack1D( newRV_noinc((SV*)point3), 'd');
2689   cpoint4 = get_mortalspace( naxes, 'd' );
2690 
2691   ASTCALL(
2692     astResolve(this, cpoint1, cpoint2, cpoint3, cpoint4, &d1, &d2);
2693   )
2694 
2695   point4 = newAV();
2696   unpack1D( newRV_noinc((SV*)point4), cpoint4, 'd', naxes);
2697 
2698   XPUSHs( newRV_noinc((SV*) point4));
2699   XPUSHs( sv_2mortal(newSVnv(d1)));
2700   XPUSHs( sv_2mortal(newSVnv(d2)));
2701 
2702 
2703 
2704 
2705 void
2706 astSetActiveUnit( this, value )
2707   AstFrame * this
2708   int value
2709  CODE:
2710 #ifndef HASSETACTIVEUNIT
2711   Perl_croak(aTHX_ "astSetActiveUnit: Please upgrade to AST V2.x or newer");
2712 #else
2713   ASTCALL(
2714    astSetActiveUnit( this, value );
2715   )
2716 #endif
2717 
2718 # astUnformat currently returns the value not the number of
2719 # characters read. Returns undef if no character read
2720 #  XXXXX
2721 
2722 double
2723 astUnformat( this, axis, string )
2724   AstFrame * this
2725   int axis
2726   char * string
2727  PREINIT:
2728   int nread;
2729  CODE:
2730   nread = astUnformat( this, axis, string, &RETVAL );
2731   if (nread == 0 ) XSRETURN_UNDEF;
2732  OUTPUT:
2733   RETVAL
2734 
2735 
2736 MODULE = Starlink::AST   PACKAGE = Starlink::AST::FrameSet PREFIX = ast
2737 
2738 void
2739 astAddFrame( this, iframe, map, frame)
2740   AstFrameSet * this
2741   int iframe
2742   AstMapping * map
2743   AstFrame * frame
2744  CODE:
2745   ASTCALL(
2746    astAddFrame( this, iframe, map, frame );
2747   )
2748 
2749 
2750 AstFrame *
2751 ast_GetFrame( this, iframe )
2752   AstFrameSet * this
2753   int iframe
2754  CODE:
2755   ASTCALL(
2756    RETVAL = astGetFrame( this, iframe );
2757   )
2758   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
2759  OUTPUT:
2760   RETVAL
2761 
2762 AstMapping *
2763 astGetMapping( this, iframe1, iframe2 )
2764   AstFrameSet * this
2765   int iframe1
2766   int iframe2
2767  CODE:
2768   ASTCALL(
2769    RETVAL = astGetMapping( this, iframe1, iframe2 );
2770   )
2771   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
2772  OUTPUT:
2773   RETVAL
2774 
2775 void
2776 astRemapFrame( this, iframe, map )
2777   AstFrameSet * this
2778   int iframe
2779   AstMapping * map
2780  CODE:
2781   ASTCALL(
2782    astRemapFrame( this, iframe, map );
2783   )
2784 
2785 void
2786 astRemoveFrame( this, iframe )
2787   AstFrameSet * this
2788   int iframe
2789  CODE:
2790   ASTCALL(
2791    astRemoveFrame( this, iframe );
2792   )
2793 
2794 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Mapping PREFIX = ast
2795 
2796 # Return the new mappings and booleans as a list
2797 # Do this later since it requires subversion of the typemap
2798 # system
2799 
2800 # XXXXX
2801 
2802 void
2803 astDecompose( this )
2804   AstMapping * this
2805  PREINIT:
2806   AstMapping * map1;
2807   AstMapping * map2;
2808   int series;
2809   int invert1;
2810   int invert2;
2811  PPCODE:
2812   Perl_croak(aTHX_ "astDecompose not yet implemented\n");
2813   /* May want to restrict this to CmpMap and CmpFrame classes
2814      explicitly */
2815   ASTCALL(
2816    astDecompose(this, &map1, &map2, &series, &invert1, &invert2);
2817   )
2818 
2819 
2820 void
2821 astInvert( this )
2822   AstMapping * this
2823  CODE:
2824   ASTCALL(
2825    astInvert( this );
2826   )
2827 
2828 void
2829 astLinearApprox( this, lbnd, ubnd, tol )
2830   AstMapping * this
2831   AV * lbnd
2832   AV * ubnd
2833   double tol
2834  PREINIT:
2835   int len;
2836   double * clbnd;
2837   double * cubnd;
2838   int nin;
2839   int nout;
2840   int ncoeff;
2841   double * fit;
2842   int i;
2843   int status;
2844  PPCODE:
2845 #ifndef HASLINEARAPPROX
2846    Perl_croak(aTHX_ "astLinearApprox: Please upgrade to AST V3.4 or greater");
2847 #else
2848   /* get the input values and verify them */
2849   nin = astGetI( this, "Nin" );
2850   len = av_len( lbnd ) + 1;
2851   if ( len != nin ) Perl_croak( aTHX_ "lbnd must contain %d elements", nin );
2852   len = av_len( ubnd ) + 1;
2853   if ( len != nin ) Perl_croak( aTHX_ "ubnd must contain %d elements", nin );
2854   clbnd = pack1D(newRV_noinc((SV*)lbnd), 'd');
2855   cubnd = pack1D(newRV_noinc((SV*)ubnd), 'd');
2856 
2857   /* Get memory for the return values */
2858   nout = astGetI( this, "Nout");
2859   ncoeff = (nin+1) * nout;
2860   fit = get_mortalspace( ncoeff, 'd' );
2861 
2862   ASTCALL(
2863     status = astLinearApprox( this, clbnd, cubnd, tol, fit );
2864   )
2865   if ( status == 0) {
2866     XSRETURN_EMPTY;
2867   } else {
2868     for (i = 0; i < ncoeff; i++) {
2869       XPUSHs( sv_2mortal( newSVnv( fit[i] ) ) );
2870     }
2871   }
2872 #endif
2873 
2874 # astMapBox
2875 # ($lbnd_out, $ubnd_out, \@xl, \@xu) = $mapping->MapBox(\@lbnd_in, \@ubnd_in, $forward, $coord_out);
2876 
2877 void
2878 astMapBox( this, lbnd_in, ubnd_in, forward, coord_out )
2879   AstMapping * this
2880   AV * lbnd_in
2881   AV * ubnd_in
2882   int forward
2883   int coord_out
2884  PREINIT:
2885   int nin;
2886   int len;
2887   double * clbnd = NULL;
2888   double * cubnd = NULL;
2889   double * cxl = NULL;
2890   double * cxu = NULL;
2891   double lbnd_out;
2892   double ubnd_out;
2893   AV * xl = NULL;
2894   AV * xu = NULL;
2895  PPCODE:
2896   nin = astGetI( this, "Nin" );
2897   len = av_len( lbnd_in ) + 1;
2898   if ( len != nin ) Perl_croak( aTHX_ "lbnd must contain %d elements", nin );
2899   len = av_len( ubnd_in ) + 1;
2900   if ( len != nin ) Perl_croak( aTHX_ "ubnd must contain %d elements", nin );
2901   clbnd = pack1D(newRV_noinc((SV*)lbnd_in), 'd' );
2902   cubnd = pack1D(newRV_noinc((SV*)ubnd_in), 'd' );
2903 
2904   /* Return arrays */
2905   cxl = get_mortalspace( nin, 'd' );
2906   cxu = get_mortalspace( nin, 'd' );
2907 
2908   ASTCALL(
2909     astMapBox( this, clbnd, cubnd, forward, coord_out,
2910                &lbnd_out, &ubnd_out, cxl, cxu );
2911   )
2912 
2913   /* Push results */
2914   XPUSHs(sv_2mortal(newSVnv(lbnd_out)));
2915   XPUSHs(sv_2mortal(newSVnv(ubnd_out)));
2916 
2917   xl = newAV();
2918   unpack1D( newRV_noinc((SV*) xl), cxl, 'd', nin );
2919   XPUSHs( newRV_noinc( (SV*)xl ));
2920   xu = newAV();
2921   unpack1D( newRV_noinc((SV*) xu), cxu, 'd', nin );
2922   XPUSHs( newRV_noinc( (SV*)xu ));
2923 
2924 
2925 # astMapSplit
2926 # One argument: The indices of the mapping to extract
2927 # Two return arguments: A mapping and a list of indices
2928 #  ($map, @indices) = $map->MapSplit( \@indices );
2929 void
2930 astMapSplit( this, in )
2931   AstMapping * this
2932   AV * in
2933  PREINIT:
2934   int i;
2935   int nin;
2936   int nout;
2937   int * cin;
2938   int * cout;
2939   AstMapping * outmap = NULL;
2940  PPCODE:
2941 #ifndef HASMAPSPLIT
2942   Perl_croak(aTHX_ "astMapSplit: Please upgrade to AST V5.3 or greater");
2943 #else
2944   nin = av_len( in ) + 1;
2945   cin = pack1D(newRV_noinc((SV*)in), 'i');
2946 
2947   /* output array */
2948   nout = astGetI( this, "Nout" );
2949   cout = get_mortalspace( nout, 'i' );
2950 
2951   ASTCALL(
2952     astMapSplit( this, nin, cin, cout, &outmap );
2953   )
2954 
2955   /* Push the results onto the stack */
2956   if (outmap) {
2957     SV * sv = createPerlObject( "AstMappingPtr", (AstObject*)outmap );
2958     XPUSHs(sv_2mortal( sv ));
2959     /* recalculate nout */
2960     nout = astGetI( outmap, "Nout" );
2961     for (i = 0; i < nout; i++) {
2962       XPUSHs( sv_2mortal( newSViv( cout[i] ) ) );
2963     }
2964   } else {
2965     XSRETURN_EMPTY;
2966   }
2967 #endif
2968 
2969 # astRate
2970 #  Returns the rate and (sometimes) the second derivatives
2971 #  Returns empty list if astRate returns AST__BAD
2972 
2973 void
2974 astRate( this, at, ax1, ax2 )
2975   AstMapping * this
2976   AV* at
2977   int ax1
2978   int ax2
2979  PREINIT:
2980   int nin;
2981   int len;
2982   double * cat;
2983   double d2;
2984  PPCODE:
2985 #ifndef HASRATE
2986    Perl_croak(aTHX_ "astRate: Please upgrade to AST V3.x or greater");
2987 #else
2988   nin = astGetI( this, "Nin");
2989   len = av_len( at ) + 1;
2990   if (nin != len)
2991       Perl_croak(aTHX_ "Must supply Nin coordinates to astRate [%d != %d]",
2992                         nin, len);
2993   cat = pack1D( newRV_noinc((SV*)at), 'd');
2994   myAstRate( this, cat ,ax1, ax2, &d2 );
2995 #endif
2996 
2997 
2998 # astResample XXXX
2999 
3000 
3001 AstMapping *
3002 astSimplify( this )
3003   AstMapping * this
3004  CODE:
3005   ASTCALL(
3006    RETVAL = astSimplify( this );
3007   )
3008   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3009  OUTPUT:
3010   RETVAL
3011 
3012 # astTran1
3013 #   Returns one array
3014 # Even though we return one array, we use PPCODE so that it is closer to
3015 # the code used for astTran2
3016 
3017 void
3018 astTran1( this, xin, forward )
3019   AstMapping * this
3020   AV* xin
3021   bool forward
3022  PREINIT:
3023   int len1;
3024   double * cxin;
3025   AV* xout;
3026   double * cxout;
3027   SV** elem;
3028  PPCODE:
3029   len1 = av_len( xin ) + 1;
3030   cxin = pack1D( newRV_noinc((SV*)xin), 'd');
3031   cxout = get_mortalspace( len1, 'd' );
3032 
3033   ASTCALL(
3034     astTran1( this, len1, cxin, forward, cxout );
3035   )
3036 
3037   xout = newAV();
3038   unpack1D( newRV_noinc((SV*) xout), cxout, 'd', len1);
3039 
3040   XPUSHs( newRV_noinc((SV*) xout ));
3041 
3042 
3043 
3044 # astTran2
3045 #   Returns 2 arrays
3046 
3047 void
3048 astTran2( this, xin, yin, forward )
3049   AstMapping * this
3050   AV* xin
3051   AV* yin
3052   bool forward
3053  PREINIT:
3054   int len1;
3055   int len2;
3056   double * cxin;
3057   double * cyin;
3058   AV* xout;
3059   AV* yout;
3060   double * cxout;
3061   double * cyout;
3062   SV** elem;
3063  PPCODE:
3064   len1 = av_len( xin ) + 1;
3065   len2 = av_len( yin ) + 1;
3066   if ( len1 != len2 )
3067      Perl_croak(aTHX_ "Number of elements in input arrays must be identical (%d != %d )",
3068              len1, len2);
3069   cxin = pack1D( newRV_noinc((SV*)xin), 'd');
3070   cyin = pack1D( newRV_noinc((SV*)yin), 'd');
3071   cxout = get_mortalspace( len1, 'd' );
3072   cyout = get_mortalspace( len2, 'd' );
3073 
3074   ASTCALL(
3075     astTran2( this, len1, cxin, cyin, forward, cxout, cyout );
3076   )
3077 
3078   xout = newAV();
3079   yout = newAV();
3080   unpack1D( newRV_noinc((SV*) xout), cxout, 'd', len1);
3081   unpack1D( newRV_noinc((SV*) yout), cyout, 'd', len2);
3082 
3083   XPUSHs( newRV_noinc((SV*) xout ));
3084   XPUSHs( newRV_noinc((SV*) yout ));
3085 
3086 
3087 
3088 # astTranN  XXXX
3089 
3090 # astTranP
3091 
3092 # Note that to allow a better perl interface, we put all the array
3093 # arguments at the end and allow an arbitrary number of coordinates
3094 # to be provided without having to use an array of arrays
3095 
3096 # To match the interface to astTranP there must be an input array
3097 # per input axis, and each array must contain the same number of elements
3098 # referring to the coordinate for a specific dimension. ie for a 2D coordinate
3099 # you will need just two arrays: the first array has all the X coordinates
3100 # and the second has all the Y coordinates.
3101 
3102 #  @transformed = $wcs->TranP( 1, [ 1,0 ], [1,-1] ... );
3103 
3104 void
3105 astTranP( this, forward, ... )
3106   AstMapping * this
3107   int forward
3108  PREINIT:
3109   int i;
3110   int n;
3111   int argoff = 2; /* number of fixed arguments */
3112   int ndims;
3113   int npoint;
3114   int naxin;
3115   int naxout;
3116   int ncoord_in;
3117   int ncoord_out;
3118   double **ptr_in;
3119   double **ptr_out;
3120  PPCODE:
3121   /* Make sure we have some coordinates to transform */
3122   ndims = items - argoff;
3123   if (ndims > 0) {
3124     /* Number of in and output coordinates required for this mapping */
3125     naxin = astGetI( this, "Nin" );
3126     naxout = astGetI( this, "Nout" );
3127 
3128     /* The required dimensionality depends on direction */
3129     if (forward) {
3130       ncoord_in = naxin;
3131       ncoord_out = naxout;
3132     } else {
3133       ncoord_in = naxout;
3134       ncoord_out = naxin;
3135     }
3136 
3137     /* Make sure that the number of supplied arguments matches the
3138        number of required input dimensions */
3139     if ( ndims != ncoord_in )
3140       Perl_croak(aTHX_ "Number of input arrays must be identical to the number of coordinates in the input frame (%d != %d )", ndims, ncoord_in);
3141 
3142     /* Get some memory for the input and output pointer arrays */
3143     ptr_in = get_mortalspace( ncoord_in, 'v' );
3144     ptr_out = get_mortalspace( ncoord_out, 'v' );
3145 
3146     /* Need to get the number of input elements in the first array */
3147     npoint = (int)nelem1D( ST(argoff) );
3148 
3149     /* Loop over all the remaining arrays and store them in an array */
3150     for (i = argoff; i<items; i++) {
3151        int count = i - argoff;
3152        /* input coordinates */
3153        ptr_in[count] = pack1D( ST(i), 'd' );
3154 
3155        /* Check size */
3156        n = nelem1D( ST(i) );
3157        if (n != npoint)
3158           Perl_croak(aTHX_ "Input array %d has differing number of elements to first array (%d != %d)",
3159                      count, n, npoint);
3160 
3161     }
3162     /* Allocate memory for the output coordinates */
3163     for (i = 0; i < ncoord_out; i++) {
3164        ptr_out[i] = get_mortalspace( npoint, 'd' );
3165     }
3166 
3167     /* Call AST */
3168     ASTCALL (
3169       astTranP( this, npoint, ncoord_in, (const double**)ptr_in, forward, ncoord_out, ptr_out);
3170     )
3171 
3172     /* Copy the output to perl */
3173     for (i = 0; i < ncoord_out; i++) {
3174        AV* outarr = newAV();
3175        unpack1D( newRV_noinc((SV*)outarr), ptr_out[i], 'd', npoint);
3176        XPUSHs( newRV_noinc((SV*)outarr) );
3177     }
3178 
3179   } else {
3180     /* no input, no output */
3181     XSRETURN_EMPTY;
3182   }
3183 
3184 MODULE = Starlink::AST   PACKAGE = Starlink::AST::RateMap
3185 
3186 AstRateMap *
3187 new( class, map, ax1, ax2, options )
3188   char * class
3189   AstMapping * map
3190   int ax1
3191   int ax2
3192   char * options
3193  CODE:
3194 #ifndef HASRATEMAP
3195   Perl_croak(aTHX_ "astRateMap: Please upgrade to AST V3.5 or newer");
3196 #else
3197   ASTCALL(
3198     RETVAL = astRateMap( map, ax1, ax2, options );
3199   )
3200   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3201 #endif
3202  OUTPUT:
3203   RETVAL
3204 
3205 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Channel PREFIX = ast
3206 
3207 AstObject *
3208 ast_Read( channel )
3209   AstChannel * channel
3210  CODE:
3211   ASTCALL(
3212    RETVAL = astRead( channel );
3213   )
3214   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3215  OUTPUT:
3216   RETVAL
3217 
3218 int
3219 astWrite( channel, object )
3220   AstChannel * channel
3221   AstObject * object
3222  CODE:
3223   ASTCALL(
3224    RETVAL = astWrite( channel, object );
3225   )
3226  OUTPUT:
3227   RETVAL
3228 
3229 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Region PREFIX = ast
3230 
3231 AstFrame *
3232 astGetRegionFrame( this )
3233   AstRegion * this
3234  CODE:
3235 #ifndef HASREGION
3236    Perl_croak(aTHX_ "astGetRegionFrame: Please upgrade to AST V3.5 or greater");
3237 #else
3238   ASTCALL(
3239     RETVAL = astGetRegionFrame( this );
3240   )
3241   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3242 #endif
3243  OUTPUT:
3244   RETVAL
3245 
3246 AstRegion *
3247 astMapRegion( this, map, frame )
3248   AstRegion * this
3249   AstMapping * map
3250   AstFrame * frame
3251  CODE:
3252 #ifndef HASREGION
3253    Perl_croak(aTHX_ "astMapRegion: Please upgrade to AST V3.5 or greater");
3254 #else
3255   ASTCALL(
3256     RETVAL = astMapRegion( this, map, frame );
3257   )
3258   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3259 #endif
3260  OUTPUT:
3261   RETVAL
3262 
3263 # Takes as input a data array and associated pixel bounds, and returns
3264 # the modified data array and the number of values masked within it.
3265 # Fortran order is assumed. This routine should really be implemented
3266 # using PDLs rather than perl linear arrays
3267 # NOT PROPERLY IMPLEMENTED
3268 
3269 void
3270 astMaskD( this, map, inside, lbnd, ubnd, in, val)
3271   AstRegion * this
3272   AstMapping * map
3273   bool inside
3274   AV * lbnd
3275   AV * ubnd
3276   AV * in
3277   double val
3278  PREINIT:
3279   int len;
3280   int ndims;
3281   int * clbnd;
3282   int * cubnd;
3283   double * cin;
3284   int nelem;
3285   int i;
3286   AV * output;
3287   int nmasked;
3288  PPCODE:
3289 #ifndef HASREGION
3290   Perl_croak(aTHX_ "astNegate: Please upgrade to AST V3.5 or greater");
3291 #else
3292   ndims = astGetI( map, "Nout" );
3293   len = av_len( lbnd ) + 1;
3294   if ( len != ndims ) Perl_croak( aTHX_ "lbnd must contain %d elements", ndims );
3295   len = av_len( ubnd ) + 1;
3296   if ( len != ndims ) Perl_croak( aTHX_ "ubnd must contain %d elements", ndims );
3297   clbnd = pack1D(newRV_noinc((SV*)lbnd), 'd');
3298   cubnd = pack1D(newRV_noinc((SV*)ubnd), 'd');
3299   cin = pack1D( newRV_noinc((SV*)in), 'd' );
3300   ASTCALL(
3301      nmasked = astMaskD( this, map, inside, ndims, clbnd, cubnd, cin, val);
3302    )
3303   /* but now need to unroll the data array into a perl array */
3304   nelem = cubnd[0] - clbnd[0];
3305   for ( i=1; i < ndims; i++ ) {
3306     nelem *= ( cubnd[i] - clbnd[i] );
3307   }
3308   output = newAV();
3309   unpack1D( newRV_noinc((SV*) output), cin, 'd', nelem);
3310   XPUSHs( newRV_noinc((SV*)output));
3311   XPUSHs( sv_2mortal(newSVnv(nmasked)));
3312 #endif
3313 
3314 void
3315 astNegate( this )
3316   AstRegion * this
3317  CODE:
3318 #ifndef HASREGION
3319    Perl_croak(aTHX_ "astNegate: Please upgrade to AST V3.5 or greater");
3320 #else
3321   ASTCALL(
3322     astNegate( this );
3323   )
3324 #endif
3325 
3326 int
3327 astOverlap( this, that )
3328   AstRegion * this
3329   AstRegion * that
3330  CODE:
3331 #ifndef HASREGION
3332    Perl_croak(aTHX_ "astOverlap: Please upgrade to AST V3.5 or greater");
3333 #else
3334   ASTCALL(
3335     RETVAL = astOverlap( this, that );
3336   )
3337 #endif
3338  OUTPUT:
3339   RETVAL
3340 
3341 void
3342 astSetUnc( this, unc )
3343   AstRegion * this
3344   AstRegion * unc
3345  CODE:
3346 #ifndef HASREGION
3347    Perl_croak(aTHX_ "astSetUnc: Please upgrade to AST V3.5 or greater");
3348 #else
3349   ASTCALL(
3350     astSetUnc( this, unc );
3351   )
3352 #endif
3353 
3354 # astGetRegionBounds
3355 # (\@lbnd, \@ubnd) = $region->GetRegionBounds();
3356 
3357 void
3358 astGetRegionBounds( this )
3359   AstRegion * this
3360  PREINIT:
3361   int naxes;
3362   int i;
3363   double * clbnd;
3364   double * cubnd;
3365   AV * lbnd;
3366   AV * ubnd;
3367  PPCODE:
3368 #ifndef HASREGION
3369   Perl_croak(aTHX_ "astGetRegionBounds: Please upgrade to AST V3.5 or greater");
3370 #else
3371   naxes = astGetI( this, "Naxes" );
3372   clbnd = get_mortalspace( naxes, 'd' );
3373   cubnd = get_mortalspace( naxes, 'd' );
3374 
3375   ASTCALL(
3376     astGetRegionBounds( this, clbnd, cubnd );
3377   )
3378 
3379   lbnd = newAV();
3380   ubnd = newAV();
3381   unpack1D( newRV_noinc((SV*) lbnd), clbnd, 'd', naxes );
3382   unpack1D( newRV_noinc((SV*) ubnd), cubnd, 'd', naxes );
3383 
3384   XPUSHs(newRV_noinc((SV*) lbnd));
3385   XPUSHs(newRV_noinc((SV*) ubnd));
3386 #endif
3387 
3388 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Ellipse
3389 
3390 AstEllipse *
3391 new( class, frame, form, centre, point1, point2, unc, options)
3392   char * class
3393   AstFrame * frame
3394   int form
3395   AV * centre
3396   AV * point1
3397   AV * point2
3398   AstRegion * unc
3399   char * options
3400  PREINIT:
3401   int naxes = 2;
3402   int len;
3403   int nreq;
3404   double * ccentre;
3405   double * cpoint1;
3406   double * cpoint2;
3407  CODE:
3408 #ifndef HASREGION
3409    Perl_croak(aTHX_ "astEllipse: Please upgrade to AST V3.5 or greater");
3410 #else
3411   len = av_len( centre ) + 1;
3412   if ( len != naxes ) Perl_croak( aTHX_ "centre must contain %d elements", naxes );
3413   len = av_len( point1 ) + 1;
3414   if ( len != 2 ) Perl_croak( aTHX_ "point1 must contain %d elements", 2 );
3415   len = av_len( point2 ) + 1;
3416   if (form == 0) {
3417     nreq = naxes;
3418   } else {
3419     nreq = 1;
3420   }
3421   if ( len != nreq ) Perl_croak( aTHX_ "point2 must contain %d elements not %d", nreq, len );
3422   ccentre = pack1D(newRV_noinc((SV*)centre), 'd');
3423   cpoint1 = pack1D(newRV_noinc((SV*)point1), 'd');
3424   cpoint2 = pack1D(newRV_noinc((SV*)point2), 'd');
3425   ASTCALL(
3426      RETVAL = astEllipse( frame, form, ccentre, cpoint1, cpoint2, unc, options);
3427   )
3428   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3429 #endif
3430  OUTPUT:
3431   RETVAL
3432 
3433 
3434 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Box
3435 
3436 AstBox *
3437 new( class, frame, form, point1, point2, unc, options )
3438   char * class
3439   AstFrame * frame
3440   int form
3441   AV * point1
3442   AV * point2
3443   AstRegion * unc
3444   char * options
3445  PREINIT:
3446   double * cpoint2;
3447   double * cpoint1;
3448   int len;
3449   int naxes;
3450  CODE:
3451 #ifndef HASREGION
3452    Perl_croak(aTHX_ "astBox: Please upgrade to AST V3.5 or greater");
3453 #else
3454   naxes = astGetI( frame, "Naxes" );
3455   len = av_len( point1 ) + 1;
3456   if ( len != naxes ) Perl_croak( aTHX_ "point1 must contain %d elements", naxes );
3457   len = av_len( point2 ) + 1;
3458   if ( len != naxes ) Perl_croak( aTHX_ "point2 must contain %d elements", naxes );
3459   cpoint1 = pack1D(newRV_noinc((SV*)point1), 'd');
3460   cpoint2 = pack1D(newRV_noinc((SV*)point2), 'd');
3461    ASTCALL(
3462      RETVAL = astBox( frame, form, cpoint1, cpoint2, unc, options);
3463    )
3464   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3465 #endif
3466  OUTPUT:
3467   RETVAL
3468 
3469 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Interval
3470 
3471 AstInterval *
3472 new( class, frame, lbnd, ubnd, unc, options )
3473   char * class
3474   AstFrame * frame
3475   AV * lbnd
3476   AV * ubnd
3477   AstRegion * unc
3478   char * options
3479  PREINIT:
3480   double * clbnd;
3481   double * cubnd;
3482   int len;
3483   int naxes;
3484  CODE:
3485 #ifndef HASREGION
3486    Perl_croak(aTHX_ "astInterval: Please upgrade to AST V3.5 or greater");
3487 #else
3488   naxes = astGetI( frame, "Naxes" );
3489   len = av_len( lbnd ) + 1;
3490   if ( len != naxes ) Perl_croak( aTHX_ "lbnd must contain %d elements", naxes );
3491   len = av_len( ubnd ) + 1;
3492   if ( len != naxes ) Perl_croak( aTHX_ "ubnd must contain %d elements", naxes );
3493   clbnd = pack1D(newRV_noinc((SV*)lbnd), 'd');
3494   cubnd = pack1D(newRV_noinc((SV*)ubnd), 'd');
3495    ASTCALL(
3496      RETVAL = astInterval( frame, clbnd, cubnd, unc, options);
3497    )
3498   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3499 #endif
3500  OUTPUT:
3501   RETVAL
3502 
3503 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Polygon
3504 
3505 # Note that the interface differs to the low level routine
3506 
3507 AstPolygon *
3508 new( class, frame, xpoints, ypoints, unc, options )
3509   char * class
3510   AstFrame * frame
3511   AV * xpoints
3512   AV * ypoints
3513   AstRegion * unc
3514   char * options
3515  PREINIT:
3516   int i;
3517   int xlen;
3518   int ylen;
3519   double * points;
3520   double * cxpoints;
3521   double * cypoints;
3522   double * x;
3523   double * y;
3524  CODE:
3525 #ifndef HASREGION
3526    Perl_croak(aTHX_ "astPolygon: Please upgrade to AST V3.5 or greater");
3527 #else
3528    /* count elements */
3529    xlen = av_len( xpoints ) + 1;
3530    ylen = av_len( ypoints ) + 1;
3531    if ( xlen != ylen ) Perl_croak( aTHX_ "number of x and y points differ (%d != %d)",
3532                            xlen, ylen );
3533    cxpoints = pack1D(newRV_noinc((SV*)xpoints), 'd');
3534    cypoints = pack1D(newRV_noinc((SV*)ypoints), 'd');
3535 
3536    /* Create memory for the array as required by AST */
3537    points = get_mortalspace( xlen * 2, 'd');
3538 
3539    /* copy points in */
3540    x = points;
3541    y = points + xlen; /* offset into the array */
3542    for (i = 0; i < xlen; i++ ) {
3543      x[i] = cxpoints[i];
3544      y[i] = cypoints[i];
3545    }
3546 
3547    ASTCALL(
3548      RETVAL = astPolygon(frame, xlen, xlen, points, unc, options );
3549    )
3550    if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3551 #endif
3552  OUTPUT:
3553   RETVAL
3554 
3555 MODULE = Starlink::AST   PACKAGE = Starlink::AST::NullRegion
3556 
3557 AstNullRegion *
3558 new( class, frame, unc, options )
3559   char * class
3560   AstFrame * frame
3561   AstRegion * unc
3562   char * options
3563  CODE:
3564 #ifndef HASREGION
3565    Perl_croak(aTHX_ "astNullRegion: Please upgrade to AST V3.5 or greater");
3566 #else
3567    ASTCALL(
3568      RETVAL = astNullRegion( frame, unc, options);
3569    )
3570   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3571 #endif
3572  OUTPUT:
3573   RETVAL
3574 
3575 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Region	PREFIX = ast
3576 
3577 # Note that we are trying to make this a method in the Region base class
3578 # so that all regions can be converted into CmpRegions
3579 
3580 AstCmpRegion *
3581 astCmpRegion( region1, region2, oper, options )
3582   AstRegion * region1
3583   AstRegion * region2
3584   int oper
3585   char * options
3586  CODE:
3587 #ifndef HASREGION
3588    Perl_croak(aTHX_ "astCmpRegion: Please upgrade to AST V3.5 or greater");
3589 #else
3590    ASTCALL(
3591      RETVAL = astCmpRegion( region1, region2, oper, options);
3592   )
3593   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3594 #endif
3595  OUTPUT:
3596   RETVAL
3597 
3598 int
3599 AST__AND()
3600  CODE:
3601 #ifdef AST__AND
3602     RETVAL = AST__AND;
3603 #else
3604     Perl_croak(aTHX_ "Constant AST__AND not defined\n");
3605 #endif
3606  OUTPUT:
3607   RETVAL
3608 
3609 int
3610 AST__OR()
3611  CODE:
3612 #ifdef AST__OR
3613     RETVAL = AST__OR;
3614 #else
3615     Perl_croak(aTHX_ "Constant AST__OR not defined\n");
3616 #endif
3617  OUTPUT:
3618   RETVAL
3619 
3620 
3621 
3622 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Circle
3623 
3624 AstCircle *
3625 new( class, frame, form, centre, point, unc, options )
3626   char * class
3627   AstFrame * frame
3628   int form
3629   AV * centre
3630   AV * point
3631   AstRegion * unc
3632   char * options
3633  PREINIT:
3634   double * ccentre;
3635   double * cpoint;
3636   int len;
3637   int naxes;
3638   int nform;
3639  CODE:
3640 #ifndef HASREGION
3641    Perl_croak(aTHX_ "astCircle: Please upgrade to AST V3.5 or greater");
3642 #else
3643   naxes = astGetI( frame, "Naxes" );
3644   len = av_len( centre ) + 1;
3645   if ( len != naxes ) Perl_croak( aTHX_ "point1 must contain %d elements", naxes );
3646   /* point depends on form */
3647   len = av_len( point ) + 1;
3648   if (form == 0) {
3649     nform = naxes;
3650   } else {
3651     nform = 1;
3652   }
3653   if ( len != nform ) Perl_croak( aTHX_ "point() must contain %d elements", nform );
3654   ccentre = pack1D(newRV_noinc((SV*)centre), 'd');
3655   cpoint = pack1D(newRV_noinc((SV*)point), 'd');
3656   ASTCALL(
3657      RETVAL = astCircle( frame, form, ccentre, cpoint, unc, options);
3658   )
3659   if ( RETVAL == AST__NULL ) XSRETURN_UNDEF;
3660 #endif
3661  OUTPUT:
3662   RETVAL
3663 
3664 
3665 MODULE = Starlink::AST   PACKAGE = Starlink::AST::FitsChan PREFIX = ast
3666 
3667 void
3668 astPutCards( this, cards )
3669   AstFitsChan * this
3670   char * cards
3671  CODE:
3672 #ifndef HASPUTCARDS
3673    Perl_croak(aTHX_ "astPutCards: Please upgrade to AST V3.2 or greater");
3674 #else
3675   ASTCALL(
3676     astPutCards( this, cards );
3677   )
3678 #endif
3679 
3680 void
3681 astPutFits( this, card, overwrite )
3682   AstFitsChan * this
3683   char * card
3684   int overwrite
3685  CODE:
3686   ASTCALL(
3687    astPutFits(this, card, overwrite);
3688   )
3689 
3690 void
3691 astDelFits( this )
3692   AstFitsChan * this
3693  CODE:
3694   ASTCALL(
3695    astDelFits( this );
3696   )
3697 
3698 # Need to handle a NULL card  - XXXXX
3699 
3700 int
3701 astFindFits( this, name, card, inc )
3702   AstFitsChan * this
3703   char * name
3704   char * card = NO_INIT
3705   int inc
3706  PREINIT:
3707   char buff[81];
3708  CODE:
3709   card = buff;
3710   ASTCALL(
3711    RETVAL = astFindFits( this, name, card, inc );
3712   )
3713  OUTPUT:
3714   RETVAL
3715   card
3716 
3717 void
3718 astSetFitsCF( this, name, real, imag, comment, overwrite )
3719   AstFitsChan * this
3720   char * name
3721   double real
3722   double imag
3723   char * comment
3724   int overwrite
3725  PREINIT:
3726   double value[2];
3727  CODE:
3728 #ifndef HASSETFITS
3729   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3730 #else
3731   value[0] = real;
3732   value[1] = imag;
3733   ASTCALL(
3734     astSetFitsCF( this, name, value, comment, overwrite );
3735   )
3736 #endif
3737 
3738 void
3739 astSetFitsCI( this, name, real, imag, comment, overwrite )
3740   AstFitsChan * this
3741   char * name
3742   int real
3743   int imag
3744   char * comment
3745   int overwrite
3746  PREINIT:
3747   int value[2];
3748  CODE:
3749 #ifndef HASSETFITS
3750   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3751 #else
3752   value[0] = real;
3753   value[1] = imag;
3754   ASTCALL(
3755     astSetFitsCI( this, name, value, comment, overwrite );
3756   )
3757 #endif
3758 
3759 
3760 void
3761 astSetFitsF( this, name, value, comment, overwrite )
3762   AstFitsChan * this
3763   char * name
3764   double value
3765   char * comment
3766   int overwrite
3767  CODE:
3768 #ifndef HASSETFITS
3769   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3770 #else
3771   ASTCALL(
3772     astSetFitsF( this, name, value, comment, overwrite );
3773   )
3774 #endif
3775 
3776 void
3777 astSetFitsI( this, name, value, comment, overwrite )
3778   AstFitsChan * this
3779   char * name
3780   int value
3781   char * comment
3782   int overwrite
3783  CODE:
3784 #ifndef HASSETFITS
3785   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3786 #else
3787   ASTCALL(
3788     astSetFitsI( this, name, value, comment, overwrite );
3789   )
3790 #endif
3791 
3792 void
3793 astSetFitsL( this, name, value, comment, overwrite )
3794   AstFitsChan * this
3795   char * name
3796   bool value
3797   char * comment
3798   int overwrite
3799  PREINIT:
3800   int bval;
3801  CODE:
3802 #ifndef HASSETFITS
3803   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3804 #else
3805   bval = ( value ? 1 : 0);
3806   ASTCALL(
3807     astSetFitsL( this, name, bval, comment, overwrite );
3808   )
3809 #endif
3810 
3811 void
3812 astSetFitsS( this, name, value, comment, overwrite )
3813   AstFitsChan * this
3814   char * name
3815   char * value
3816   char * comment
3817   int overwrite
3818  CODE:
3819 #ifndef HASSETFITS
3820   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3821 #else
3822   ASTCALL(
3823     astSetFitsS( this, name, value, comment, overwrite );
3824   )
3825 #endif
3826 
3827 void
3828 astSetFitsCN( this, name, value, comment, overwrite )
3829   AstFitsChan * this
3830   char * name
3831   char * value
3832   char * comment
3833   int overwrite
3834  CODE:
3835 #ifndef HASSETFITS
3836   Perl_croak(aTHX_ "astSetFitsX: Please upgrade to AST v3.5 or newer");
3837 #else
3838   ASTCALL(
3839     astSetFitsCN( this, name, value, comment, overwrite );
3840   )
3841 #endif
3842 
3843 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SpecFrame PREFIX = ast
3844 
3845 void
3846 astSetRefPos( this, frm, lon, lat)
3847   AstSpecFrame * this
3848   AstSkyFrame * frm
3849   double lon
3850   double lat
3851  CODE:
3852 #ifndef HASSETREFPOS
3853   Perl_croak(aTHX_ "astSetRefPos: Please upgrade to AST v2.x or newer");
3854 #else
3855   ASTCALL(
3856    astSetRefPos( this, frm, lon, lat );
3857   )
3858 #endif
3859 
3860 # XXX frm is allowed to be null here
3861 
3862 void
3863 astGetRefPos( this, frm )
3864   AstSpecFrame * this
3865   AstSkyFrame * frm
3866  PREINIT:
3867   double lon;
3868   double lat;
3869  PPCODE:
3870 #ifndef HASGETREFPOS
3871   Perl_croak(aTHX_ "astGetRefPos: Please upgrade to AST v2.x or newer");
3872 #else
3873   ASTCALL(
3874    astGetRefPos( this, frm, &lon, &lat );
3875   )
3876   XPUSHs(sv_2mortal(newSVnv(lon)));
3877   XPUSHs(sv_2mortal(newSVnv(lat)));
3878 #endif
3879 
3880 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SlaMap PREFIX = astSla
3881 
3882 void
3883 astSlaAdd( this, cvt, args )
3884   AstSlaMap * this
3885   char * cvt
3886   AV* args
3887  PREINIT:
3888   double * cargs;
3889  CODE:
3890   cargs = pack1D(newRV_noinc((SV*)args), 'd');
3891   ASTCALL(
3892    astSlaAdd( this, cvt, cargs );
3893   )
3894 
3895 MODULE = Starlink::AST   PACKAGE = Starlink::AST::SpecMap PREFIX = astSpec
3896 
3897 void
3898 astSpecAdd( this, cvt, args )
3899   AstSpecMap * this
3900   char * cvt
3901   AV* args
3902  PREINIT:
3903   double * cargs;
3904  CODE:
3905   cargs = pack1D(newRV_noinc((SV*)args), 'd');
3906 #ifndef HASSPECADD
3907   Perl_croak(aTHX_ "astSpecAdd: Please upgrade to AST v2.x or newer");
3908 #else
3909   ASTCALL(
3910    astSpecAdd( this, cvt, cargs );
3911   )
3912 #endif
3913 
3914 MODULE = Starlink::AST   PACKAGE = Starlink::AST::Plot  PREFIX = ast
3915 
3916 void
3917 astBorder( this )
3918   AstPlot * this
3919  PREINIT:
3920   SV* arg = ST(0);
3921  CODE:
3922   PLOTCALL(arg,
3923 	   astBorder(this);
3924   )
3925 
3926 void
3927 astBoundingBox( this )
3928   AstPlot * this
3929  PREINIT:
3930   float clbnd[2];
3931   float cubnd[2];
3932   AV* lbnd;
3933   AV* ubnd;
3934   SV * arg = ST(0);
3935  PPCODE:
3936   PLOTCALL (arg,
3937    astBoundingBox( this, clbnd, cubnd );
3938   )
3939   lbnd = newAV();
3940   unpack1D( newRV_noinc((SV*) lbnd), clbnd, 'f', 2 );
3941   ubnd = newAV();
3942   unpack1D( newRV_noinc((SV*) ubnd), cubnd, 'f', 2 );
3943   XPUSHs(newRV_noinc((SV*)lbnd ));
3944   XPUSHs(newRV_noinc((SV*)ubnd ));
3945 
3946 
3947 void
3948 astClip( this, iframe, lbnd, ubnd )
3949   AstPlot * this
3950   int iframe
3951   AV* lbnd
3952   AV* ubnd
3953  PREINIT:
3954   int len;
3955   double * clbnd;
3956   double * cubnd;
3957   int naxes;
3958   SV * arg = ST(0);
3959  CODE:
3960   naxes = astGetI( this, "Naxes" );
3961   len = av_len( lbnd ) + 1;
3962   if ( len != naxes ) Perl_croak( aTHX_ "lbnd must contain %d elements", naxes );
3963   len = av_len( ubnd ) + 1;
3964   if ( len != naxes ) Perl_croak( aTHX_ "ubnd must contain %d elements", naxes );
3965   clbnd = pack1D(newRV_noinc((SV*)lbnd), 'd');
3966   cubnd = pack1D(newRV_noinc((SV*)ubnd), 'd');
3967   PLOTCALL (arg,
3968    astClip( this, iframe, clbnd, cubnd );
3969   )
3970 
3971 void
3972 astCurve( this, start, finish )
3973   AstPlot * this
3974   AV* start
3975   AV* finish
3976  PREINIT:
3977   int len;
3978   double * cstart;
3979   double * cfinish;
3980   int naxes;
3981   SV* arg = ST(0);
3982  CODE:
3983   naxes = astGetI(this, "Naxes" );
3984   len = av_len( start ) + 1;
3985   if ( len != naxes ) Perl_croak( aTHX_ "start must contain %d elements", naxes );
3986   len = av_len( finish ) + 1;
3987   if ( len != naxes ) Perl_croak( aTHX_ "finish must contain %d elements", naxes);
3988   cstart = pack1D(newRV_noinc((SV*)start), 'd');
3989   cfinish = pack1D(newRV_noinc((SV*)finish), 'd');
3990   PLOTCALL (arg,
3991    astCurve( this, cstart, cfinish );
3992   )
3993 
3994 void
3995 astGenCurve( this, map )
3996   AstPlot * this
3997   AstMapping * map
3998  PREINIT:
3999   SV * arg = ST(0);
4000  CODE:
4001   PLOTCALL(arg,
4002    astGenCurve(this, map);
4003   )
4004 
4005 void
4006 astGrid( this )
4007   AstPlot * this
4008  PREINIT:
4009   SV * arg = ST(0);
4010  CODE:
4011   PLOTCALL(arg,
4012    astGrid(this);
4013   )
4014 
4015 void
4016 astGridLine( this, axis, start, length )
4017   AstPlot * this
4018   int axis
4019   AV* start
4020   double length
4021  PREINIT:
4022   double * cstart;
4023   int naxes;
4024   int len;
4025   SV * arg = ST(0);
4026  CODE:
4027   naxes = astGetI( this, "Naxes" );
4028   len = av_len( start ) + 1;
4029   if ( len != naxes ) Perl_croak( aTHX_ "start must contain %d elements", naxes );
4030   cstart = pack1D(newRV_noinc((SV*)start), 'd');
4031   PLOTCALL(arg,
4032     astGridLine( this, axis, cstart, length );
4033   )
4034 
4035 # Make this a little different to the published interface
4036 # By requesting @x and @y rather than an array of coordinate doublets.
4037 
4038 void
4039 astMark(this, type, ...)
4040   AstPlot * this
4041   int type
4042  PREINIT:
4043   double * cin;
4044   int ncoords;
4045   int nmarks = 0;
4046   int indim;
4047   int size;
4048   int i;
4049   int total;
4050   int argoff = 2; /* number of fixed arguments */
4051   int naxes;
4052   SV * arg = ST(0);
4053  CODE:
4054   /* First make sure we have some arguments */
4055     if (items > argoff ) {
4056     /* Number of dimensions should be just the number of stack items */
4057     ncoords = items - argoff;
4058 
4059     /* and this should equal the number of axes in the frame */
4060     naxes = astGetI( this, "Naxes" );
4061 
4062     if ( naxes != ncoords )
4063          Perl_croak(aTHX_ "Number of supplied coordinate sets must equal number of axes in frame [%d != %d]",naxes,ncoords);
4064 
4065     /* Now go through each finding out how long each array is */
4066     for (i = argoff + 1; i<=items; i++ ) {
4067         int nelem;
4068         int index = i - 1;
4069         SV * coordsv = ST(index);
4070         AV * curr;
4071         if (SvROK(coordsv) && SvTYPE(SvRV(coordsv)) == SVt_PVAV) {
4072           curr = (AV*)SvRV( coordsv );
4073           nelem = av_len( curr ) + 1;
4074           if (i == argoff + 1) {
4075             /* No previous values */
4076             nmarks = nelem;
4077           } else if (nmarks != nelem) {
4078             Perl_croak(aTHX_ "All coordinates must have same number of elements [%d != %d]",nmarks, nelem);
4079           }
4080         } else {
4081           Perl_croak(aTHX_ "Argument %d to Mark() must be ref to array",i);
4082         }
4083     }
4084 
4085     /* Get some memory for the array */
4086     total = nmarks * ncoords;
4087     cin = get_mortalspace( total, 'd');
4088 
4089     /* and go through the arrays again (but less checking now) */
4090     for (i = 0; i < ncoords; i++ ) {
4091         int j;
4092         int argpos = i + argoff;
4093         AV * curr = (AV*)SvRV( ST(argpos) );
4094 
4095         for (j = 0; j < nmarks ; j ++ ) {
4096           SV ** elem = av_fetch( curr, j, 0);
4097           double dtmp;
4098           if (elem == NULL ) {
4099              /* undef */
4100              dtmp = 0.0;
4101           } else {
4102              dtmp = SvNV( *elem );
4103           }
4104           /* use pointer arithmetic to make sure that things align
4105              the way AST expects */
4106           *(cin + (i * nmarks) + j) = dtmp;
4107         }
4108     }
4109 
4110     /* Now call the AST routine */
4111     PLOTCALL( arg,
4112        astMark( this, nmarks, ncoords, nmarks, cin, type );
4113     )
4114 
4115   } else {
4116     XSRETURN_EMPTY;
4117   }
4118 
4119 # Make this a little different to the published interface
4120 # By requesting @x and @y rather than an array of coordinate doublets.
4121 # [code identical to astMark without the type]
4122 
4123 void
4124 astPolyCurve(this, ...)
4125   AstPlot * this
4126  PREINIT:
4127   double * cin;
4128   int ncoords;
4129   int npoints = 0;
4130   int indim;
4131   int size;
4132   int i;
4133   int total;
4134   int argoff = 1; /* number of fixed arguments */
4135   int naxes;
4136   SV * arg = ST(0);
4137  CODE:
4138   /* First make sure we have some arguments */
4139   if (items > argoff ) {
4140     /* Number of dimensions should be just the number of stack items */
4141     ncoords = items - argoff;
4142 
4143     /* and this should equal the number of axes in the frame */
4144     naxes = astGetI( this, "Naxes" );
4145 
4146     if ( naxes != ncoords )
4147          Perl_croak(aTHX_ "Number of supplied coordinate sets must equal number of axes in frame [%d != %d]",naxes,ncoords);
4148 
4149     /* Now go through each finding out how long each array is */
4150     for (i = argoff + 1; i<=items; i++ ) {
4151         int nelem;
4152         int index = i - 1;
4153         SV * coordsv = ST(index);
4154         AV * curr;
4155         if (SvROK(coordsv) && SvTYPE(SvRV(coordsv)) == SVt_PVAV) {
4156           curr = (AV*)SvRV( coordsv );
4157           nelem = av_len( curr ) + 1;
4158           if (i == argoff + 1) {
4159             /* No previous values */
4160             npoints = nelem;
4161           } else if (npoints != nelem) {
4162             Perl_croak(aTHX_ "All coordinates must have same number of elements [%d != %d]",npoints, nelem);
4163           }
4164         } else {
4165           Perl_croak(aTHX_ "Argument %d to Mark() must be ref to array",i);
4166         }
4167     }
4168 
4169     /* Get some memory for the array */
4170     total = npoints * ncoords;
4171     cin = get_mortalspace( total, 'd');
4172 
4173     /* and go through the arrays again (but less checking now) */
4174     for (i = 0; i < ncoords; i++ ) {
4175         int j;
4176         int argpos = i + argoff;
4177         AV * curr = (AV*)SvRV( ST(argpos) );
4178 
4179         for (j = 0; j < npoints ; j ++ ) {
4180           SV ** elem = av_fetch( curr, j, 0);
4181           double dtmp;
4182           if (elem == NULL ) {
4183              /* undef */
4184              dtmp = 0.0;
4185           } else {
4186              dtmp = SvNV( *elem );
4187           }
4188           /* use pointer arithmetic to make sure that things align
4189              the way AST expects */
4190           *(cin + (i * npoints) + j) = dtmp;
4191         }
4192     }
4193 
4194     /* Now call the AST routine */
4195     PLOTCALL( arg,
4196        astPolyCurve( this, npoints, ncoords, npoints, cin );
4197     )
4198 
4199   } else {
4200     XSRETURN_EMPTY;
4201   }
4202 
4203 void
4204 astText( this, text, pos, up, just )
4205   AstPlot * this
4206   char * text
4207   AV* pos
4208   AV* up
4209   char * just
4210  PREINIT:
4211   int len;
4212   float * cup;
4213   double * cpos;
4214   int naxes;
4215   SV * arg = ST(0);
4216  CODE:
4217   naxes = astGetI( this, "Naxes" );
4218   len = av_len( pos ) + 1;
4219   if ( len != naxes ) Perl_croak( aTHX_ "pos must contain %d elements", naxes);
4220   len = av_len( up ) + 1;
4221   if ( len != 2 ) Perl_croak( aTHX_ "up must contain 2 elements");
4222   cpos = pack1D(newRV_noinc((SV*)pos), 'd');
4223   cup = pack1D(newRV_noinc((SV*)up), 'f');
4224   PLOTCALL(arg,
4225     astText( this, text, cpos, cup, just );
4226   )
4227 
4228 
4229 # Constants
4230 
4231 # Start with errors. Bless them into class Starlink::AST::Status
4232 
4233 INCLUDE: AST_ERR.xsh
4234 
4235 # Then the WcsMap constants
4236 
4237 INCLUDE: AST_WCSMAP.xsh
4238 
4239 # Then the Grf constants
4240 
4241 INCLUDE: AST_GRF.xsh
4242