----- Original Message -----
From: "Chris Marshall" <[email protected]>
Note that PDL-2.4.4_13 requires OpenGL-0.58_007 to build.
Problems, successes, debugging reports welcome!
As I've mentioned, wrt Win32, OpenGL-0.58 builds and tests ok with Visual
Studio compiler, but the later developer releases of OpenGL-0.58_xxx won't
compile with that compiler because of changes to pogl_glu.xs.
I don't understand the new code in pogl_glu.xs - is there any chance of
getting the person that made those changes to re-implement them portably ?
I have verified that if I take pogl_glu.xs from 0.58, and use it in
0.58_007, then 0.58_007 builds and tests fine - and PDL-2.4.4_13 builds and
tests fine, including t/opengl.t.
But, presumably the changes to pogl_glu.xs serve a purpose, and should not
be ignored.
To reiterate - the failure I get when using the new pogl_glu.xs:
###########################################
C:\.cpan\build\OpenGL-0.58_007-cfFFmi>nmake test
Microsoft (R) Program Maintenance Utility Version 7.00.9466
Copyright (C) Microsoft Corporation. All rights reserved.
cp OpenGL.pm blib\lib/OpenGL.pm
AutoSplitting blib\lib/OpenGL.pm (blib\lib\auto\OpenGL)
cp Config.pm blib\lib/OpenGL/Config.pm
cp OpenGL.pod blib\lib/OpenGL.pod
C:\_32\perl_vc7\5.10.0\bin\perl.exe
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\
xsubpp -noprototypes -typemap
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\typemap -typem
ap typemap OpenGL.xs > OpenGL.xsc &&
C:\_32\perl_vc7\5.10.0\bin\perl.exe -MExtU
tils::Command -e mv OpenGL.xsc OpenGL.c
cl -c -nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_ST
RICT -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
/ogity /GDs -DVERSION=\"0.58_007\" -DXS_VERSION=\"0.58_007\"
"-IC:\_32\perl
_vc7\5.10.0\lib\CORE" -DHAVE_VER -DHAVE_FREEGLUT -DHAVE_FREEGLUT32 -DHAVE_GL
-D
HAVE_GLU -DHAVE_GLU32 -DHAVE_GLUT -DHAVE_GLUT32 -DHAVE_OPENGL32 OpenGL.c
cl : Command line warning D4002 : ignoring unknown option '/GD'
OpenGL.c
cl -c -nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_ST
RICT -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
/ogity /GDs -DVERSION=\"0.58_007\" -DXS_VERSION=\"0.58_007\"
"-IC:\_32\perl
_vc7\5.10.0\lib\CORE" -DHAVE_VER -DHAVE_FREEGLUT -DHAVE_FREEGLUT32 -DHAVE_GL
-D
HAVE_GLU -DHAVE_GLU32 -DHAVE_GLUT -DHAVE_GLUT32 -DHAVE_OPENGL32 gl_util.c
cl : Command line warning D4002 : ignoring unknown option '/GD'
gl_util.c
C:\_32\perl_vc7\5.10.0\bin\perl.exe
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\
xsubpp -noprototypes -typemap
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\typemap -typem
ap typemap pogl_const.xs > pogl_const.xsc &&
C:\_32\perl_vc7\5.10.0\bin\perl.ex
e -MExtUtils::Command -e mv pogl_const.xsc pogl_const.c
cl -c -nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_ST
RICT -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
/ogity /GDs -DVERSION=\"0.58_007\" -DXS_VERSION=\"0.58_007\"
"-IC:\_32\perl
_vc7\5.10.0\lib\CORE" -DHAVE_VER -DHAVE_FREEGLUT -DHAVE_FREEGLUT32 -DHAVE_GL
-D
HAVE_GLU -DHAVE_GLU32 -DHAVE_GLUT -DHAVE_GLUT32 -DHAVE_OPENGL32 pogl_const.c
cl : Command line warning D4002 : ignoring unknown option '/GD'
pogl_const.c
C:\_32\perl_vc7\5.10.0\bin\perl.exe
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\
xsubpp -noprototypes -typemap
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\typemap -typem
ap typemap pogl_gl_top.xs > pogl_gl_top.xsc &&
C:\_32\perl_vc7\5.10.0\bin\perl.
exe -MExtUtils::Command -e mv pogl_gl_top.xsc pogl_gl_top.c
cl -c -nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_ST
RICT -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
/ogity /GDs -DVERSION=\"0.58_007\" -DXS_VERSION=\"0.58_007\"
"-IC:\_32\perl
_vc7\5.10.0\lib\CORE" -DHAVE_VER -DHAVE_FREEGLUT -DHAVE_FREEGLUT32 -DHAVE_GL
-D
HAVE_GLU -DHAVE_GLU32 -DHAVE_GLUT -DHAVE_GLUT32 -DHAVE_OPENGL32
pogl_gl_top.c
cl : Command line warning D4002 : ignoring unknown option '/GD'
pogl_gl_top.c
C:\_32\perl_vc7\5.10.0\bin\perl.exe
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\
xsubpp -noprototypes -typemap
C:\_32\perl_vc7\5.10.0\lib\ExtUtils\typemap -typem
ap typemap pogl_glu.xs > pogl_glu.xsc &&
C:\_32\perl_vc7\5.10.0\bin\perl.exe -M
ExtUtils::Command -e mv pogl_glu.xsc pogl_glu.c
cl -c -nologo -GF -W3 -MD -Zi -DNDEBUG -O1 -DWIN32 -D_CONSOLE -DNO_ST
RICT -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO
/ogity /GDs -DVERSION=\"0.58_007\" -DXS_VERSION=\"0.58_007\"
"-IC:\_32\perl
_vc7\5.10.0\lib\CORE" -DHAVE_VER -DHAVE_FREEGLUT -DHAVE_FREEGLUT32 -DHAVE_GL
-D
HAVE_GLU -DHAVE_GLU32 -DHAVE_GLUT -DHAVE_GLUT32 -DHAVE_OPENGL32 pogl_glu.c
cl : Command line warning D4002 : ignoring unknown option '/GD'
pogl_glu.c
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(117) : warning C4244: 'function' : conversion from 'GLdouble' to
'GL
float', possible loss of data
pogl_glu.xs(119) : error C2275: 'GLdouble' : illegal use of this type as an
expression
c:\.cpan\build\OpenGL-0.58_007-cfFFmi\include\GL\gl.h(44) : see
declaration of 'GLdouble'
pogl_glu.xs(119) : error C2065: 'vd' : undeclared identifier
pogl_glu.xs(121) : error C2109: subscript requires array or pointer type
pogl_glu.xs(121) : error C2198: 'Perl_newSVnv' : too few actual parameters
pogl_glu.xs(184) : error C2275: 'SV' : illegal use of this type as an
expression
C:\_32\perl_vc7\5.10.0\lib\CORE\perl.h(2351) : see declaration of
'SV'
pogl_glu.xs(184) : error C2065: 'item' : undeclared identifier
pogl_glu.xs(185) : error C2275: 'GLdouble' : illegal use of this type as an
expression
c:\.cpan\build\OpenGL-0.58_007-cfFFmi\include\GL\gl.h(44) : see
declaration of 'GLdouble'
pogl_glu.xs(185) : error C2146: syntax error : missing ';' before identifier
'val'
pogl_glu.xs(185) : error C2144: syntax error : '<Unknown>' should be
preceded by
'<Unknown>'
pogl_glu.xs(185) : error C2144: syntax error : '<Unknown>' should be
preceded by
'<Unknown>'
pogl_glu.xs(185) : error C2143: syntax error : missing ';' before
'identifier'
pogl_glu.xs(185) : error C2065: 'val' : undeclared identifier
pogl_glu.xs(187) : warning C4047: '=' : 'int' differs in levels of
indirection f
rom 'SV *'
pogl_glu.xs(188) : error C2223: left of '->sv_flags' must point to
struct/union
pogl_glu.xs(188) : error C2223: left of '->sv_flags' must point to
struct/union
pogl_glu.xs(190) : error C2223: left of '->sv_flags' must point to
struct/union
pogl_glu.xs(190) : error C2223: left of '->sv_any' must point to
struct/union
pogl_glu.xs(190) : warning C4047: 'function' : 'SV *' differs in levels of
indirection from 'int'
pogl_glu.xs(190) : fatal error C1903: unable to recover from previous
error(s);
stopping compilation
NMAKE : fatal error U1077: 'cl' : return code '0x2'
Stop.
###########################################
Also, I've attached a diff of the changes made from the old pogl_glu.xs that
shipped with 0.58 and the new pogl_glu.xs as it appears in 0.58_007.
Perhaps someone with a few more tuits than me can see what's required.
Cheers,
Rob
--- pogl_glu.xs Sat Oct 3 20:02:24 2009
+++ pogl_glu.xs_new Sat Oct 3 20:02:34 2009
@@ -29,9 +29,13 @@
#ifdef IN_POGL_GLU_XS
+#ifndef CALLBACK
+#define CALLBACK
+#endif
+
/* Begin a named callback handler */
-#define begin_void_specific_marshaller(name, assign_handler_av, params) \
-static void _s_marshal_ ## name params \
+#define begin_void_specific_marshaller(name, assign_handler_av, params,
default_handler) \
+void CALLBACK _s_marshal_ ## name params \
{ \
SV * handler; \
AV * handler_av; \
@@ -40,6 +44,10 @@
assign_handler_av; \
if (!handler_av) croak("Failure of callback handler"); \
handler = *av_fetch(handler_av, 0, 0); \
+ if (! SvROK(handler)) { /* DEFAULT */ \
+ default_handler; \
+ return; \
+ } \
PUSHMARK(sp); \
for (i=1; i<=av_len(handler_av); i++) \
XPUSHs(sv_2mortal(newSVsv(*av_fetch(handler_av, i, 0))));
@@ -52,7 +60,7 @@
struct PGLUtess {
- GLUtriangulatorObj * triangulator;
+ GLUtesselator * triangulator;
#ifdef GLU_VERSION_1_2
AV * polygon_data_av;
@@ -73,51 +81,118 @@
/* Begin a gluTess callback handler */
-#define begin_tess_marshaller(type, params) \
+#define begin_tess_marshaller(type, params, default_handler) \
begin_void_specific_marshaller(glu_t_callback_ ## type, \
PGLUtess * t = (PGLUtess*)polygon_data; \
handler_av = t-> type ## _callback \
- , params) \
- if (t->polygon_data_av) \
- for (i=0; i<=av_len(t->polygon_data_av); i++) \
- XPUSHs(sv_2mortal(newSVsv(*av_fetch(t->polygon_data_av, i, 0))));
+ , params, default_handler)
/* End a gluTess callback handler */
#define end_tess_marshaller() \
+ if (t->polygon_data_av) \
+ for (i=0; i<=av_len(t->polygon_data_av); i++) \
+ XPUSHs(sv_2mortal(newSVsv(*av_fetch(t->polygon_data_av, i, 0)))); \
end_void_specific_marshaller()
/* Declare gluTess BEGIN */
-begin_tess_marshaller(begin, (GLenum type, void * polygon_data))
+begin_tess_marshaller(begin, (GLenum type, void * polygon_data), glBegin(type))
XPUSHs(sv_2mortal(newSViv(type)));
end_tess_marshaller()
/* Declare gluTess END */
-begin_tess_marshaller(end, (void * polygon_data))
+begin_tess_marshaller(end, (void * polygon_data), glEnd())
end_tess_marshaller()
/* Declare gluTess EDGEFLAG */
-begin_tess_marshaller(edgeFlag, (GLboolean flag, void * polygon_data))
+begin_tess_marshaller(edgeFlag, (GLboolean flag, void * polygon_data),
glEdgeFlag(flag))
XPUSHs(sv_2mortal(newSViv(flag)));
end_tess_marshaller()
/* Declare gluTess VERTEX */
-begin_tess_marshaller(vertex, (void * vertex_data, void * polygon_data))
- if (vertex_data) {
- AV * vd = (AV*)vertex_data;
- for (i=0; i<=av_len(vd); i++)
- XPUSHs(sv_2mortal(newSVsv(*av_fetch(vd, i, 0))));
- }
+begin_tess_marshaller(vertex, \
+ (void * vertex_data, void * polygon_data), \
+ GLdouble * vd = (GLdouble*) vertex_data; \
+ glColor3f(vd[3], vd[4], vd[5]); \
+ glVertex3f(vd[0], vd[1], vd[2]); \
+ )
+ if (! vertex_data) croak("Missing vertex data in tess vertex callback");
+ GLdouble * vd = (GLdouble*) vertex_data;
+ for (i=0; i<7; i++)
+ XPUSHs(sv_2mortal(newSVnv(vd[i])));
end_tess_marshaller()
/* Declare gluTess ERROR */
-begin_tess_marshaller(error, (GLenum errno_, void * polygon_data))
+begin_tess_marshaller(error, \
+ (GLenum errno_, void * polygon_data), \
+ warn("Tesselation error: %s", gluErrorString(errno_)) \
+ )
XPUSHs(sv_2mortal(newSViv(errno_)));
end_tess_marshaller()
/* Declare gluTess COMBINE */
-begin_tess_marshaller(combine, (GLdouble coords[3], void * vertex_data[4],
GLfloat weight[4], void ** outd, void * polygon_data))
- croak("combine tess marshaller needs FIXME (see OpenGL.xs)");
-end_tess_marshaller()
+void CALLBACK _s_marshal_glu_t_callback_combine (GLdouble coords[3], GLdouble
* vertex_data[4],
+ GLfloat weight[4], GLdouble
** out_data,
+ void * polygon_data)
+{
+ SV * handler;
+ AV * handler_av;
+ AV * vds;
+ I32 n;
+ int i, j;
+ dSP;
+ PGLUtess * t = (PGLUtess*)polygon_data;
+
+ GLdouble *vertex = malloc(sizeof(GLdouble) * 7);
+ if (vertex == NULL) croak("Couldn't allocate combination vertex during
tesselation");
+ vds = t->vertex_datas;
+ if (!vds) croak("Missing vertex data storage");
+ av_push(vds, newSViv((int)vertex));
+ *out_data = vertex;
+
+ handler_av = t->combine_callback;
+ if (!handler_av) croak("Failure of callback handler");
+ handler = *av_fetch(handler_av, 0, 0);
+
+ if (! SvROK(handler)) { /* DEFAULT */
+ vertex[0] = coords[0];
+ vertex[1] = coords[1];
+ vertex[2] = coords[2];
+ for (i=3; i<7; i++) {
+ vertex[i] = 0;
+ for (j=0; j<4; j++)
+ if (weight[j]) vertex[i] += weight[j]*vertex_data[j][i];
+ }
+ } else {
+ for (i=1; i<=av_len(handler_av); i++)
+ XPUSHs(sv_2mortal(newSVsv(*av_fetch(handler_av, i, 0))));
+
+ PUSHMARK(sp);
+ for (i = 0; i < 3; i++)
+ XPUSHs(sv_2mortal(newSVnv(coords[i])));
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 7; j++)
+ XPUSHs(sv_2mortal(newSVnv(weight[i] ? vertex_data[i][j] : 0.0)));
+ for (i = 0; i < 4; i++)
+ XPUSHs(sv_2mortal(newSVnv(weight[i])));
+ if (t->polygon_data_av)
+ for (i=0; i<=av_len(t->polygon_data_av); i++)
+ XPUSHs(sv_2mortal(newSVsv(*av_fetch(t->polygon_data_av, i, 0))));
+ PUTBACK;
+ n = perl_call_sv(handler, G_ARRAY);
+ SPAGAIN;
+ if (n != 7) croak("Need 7 values returned from callback -
x,y,z,r,g,b,a");
+ SV * item;
+ GLdouble val;
+ for (i = 6; i >= 0; i--) {
+ item = POPs;
+ if (! item || (! SvIOK(item) && ! SvNOK(item)))
+ croak("Value returned in index %d was not a valid number", i);
+ val = (GLdouble)SvNV(item);
+ vertex[i] = val;
+ }
+ PUTBACK;
+ }
+}
#endif
@@ -602,9 +677,9 @@
#void
#gluQuadricCallback
-#// gluTessBeginCountour(tess);
+#// gluTessBeginContour(tess);
void
-gluTessBeginCountour(tess)
+gluTessBeginContour(tess)
PGLUtess * tess
CODE:
gluTessBeginContour(tess->triangulator);
@@ -630,6 +705,8 @@
tess->polygon_data_av = newAV();
PackCallbackST(tess->polygon_data_av, 1);
}
+ if (!tess->vertex_datas)
+ tess->vertex_datas = newAV();
gluTessBeginPolygon(tess->triangulator, tess);
}
@@ -639,6 +716,18 @@
PGLUtess * tess
CODE:
{
+ gluTessEndPolygon(tess->triangulator);
+ if (tess->vertex_datas) {
+ AV * vds = tess->vertex_datas;
+ SV** svp;
+ I32 i;
+ for (i=0; i<=av_len(vds); i++) {
+ svp = av_fetch(vds, i, FALSE);
+ free((GLdouble*)SvIV(*svp));
+ }
+ SvREFCNT_dec(tess->vertex_datas);
+ tess->vertex_datas = 0;
+ }
if (tess->polygon_data_av) {
SvREFCNT_dec(tess->polygon_data_av);
tess->polygon_data_av = 0;
@@ -686,22 +775,77 @@
tess->end_callback = 0;
}
break;
+ case GLU_TESS_VERTEX:
+ case GLU_TESS_VERTEX_DATA:
+ if (tess->vertex_callback) {
+ SvREFCNT_dec(tess->vertex_callback);
+ tess->vertex_callback = 0;
+ }
+ break;
+ case GLU_TESS_ERROR:
+ case GLU_TESS_ERROR_DATA:
+ if (tess->error_callback) {
+ SvREFCNT_dec(tess->error_callback);
+ tess->error_callback = 0;
+ }
+ break;
+ case GLU_TESS_COMBINE:
+ case GLU_TESS_COMBINE_DATA:
+ if (tess->combine_callback) {
+ SvREFCNT_dec(tess->combine_callback);
+ tess->combine_callback = 0;
+ }
+ break;
+ case GLU_TESS_EDGE_FLAG:
+ case GLU_TESS_EDGE_FLAG_DATA:
+ if (tess->edgeFlag_callback) {
+ SvREFCNT_dec(tess->edgeFlag_callback);
+ tess->edgeFlag_callback = 0;
+ }
+ break;
}
-
- if ((items > 3) && !SvOK(ST(2))) {
- AV * callback = newAV();
- PackCallbackST(callback, 2);
+ // if ((items > 2) && !SvOK(ST(2))) {
+ if (items > 2) {
+ AV * callback = newAV();
+ if (SvPOK(ST(2))
+ && sv_eq(ST(2), sv_2mortal(newSVpv("DEFAULT", 0))))
{
+ av_push(callback, newSViv(1));
+ } else if (!SvROK(ST(2)) || SvTYPE(SvRV(ST(2))) !=
SVt_PVCV) {
+ croak("3rd argument to gluTessCallback must be a
perl code ref");
+ } else {
+ PackCallbackST(callback, 2);
+ }
switch (which) {
case GLU_TESS_BEGIN:
case GLU_TESS_BEGIN_DATA:
tess->begin_callback = callback;
- gluTessCallback(tess->triangulator, which,
(void (CALLBACK*)()) _s_marshal_glu_t_callback_begin);
+ gluTessCallback(tess->triangulator,
GLU_TESS_BEGIN_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_begin);
break;
case GLU_TESS_END:
case GLU_TESS_END_DATA:
tess->end_callback = callback;
- gluTessCallback(tess->triangulator, which,
(void (CALLBACK*)()) _s_marshal_glu_t_callback_end);
+ gluTessCallback(tess->triangulator,
GLU_TESS_END_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_end);
+ break;
+ case GLU_TESS_VERTEX:
+ case GLU_TESS_VERTEX_DATA:
+ tess->vertex_callback = callback;
+ gluTessCallback(tess->triangulator,
GLU_TESS_VERTEX_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_vertex);
+ break;
+ case GLU_TESS_ERROR:
+ case GLU_TESS_ERROR_DATA:
+ tess->error_callback = callback;
+ gluTessCallback(tess->triangulator,
GLU_TESS_ERROR_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_error);
+ break;
+ case GLU_TESS_COMBINE:
+ case GLU_TESS_COMBINE_DATA:
+ tess->combine_callback = callback;
+ gluTessCallback(tess->triangulator,
GLU_TESS_COMBINE_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_combine);
+ break;
+ case GLU_TESS_EDGE_FLAG:
+ case GLU_TESS_EDGE_FLAG_DATA:
+ tess->edgeFlag_callback = callback;
+ gluTessCallback(tess->triangulator,
GLU_TESS_EDGE_FLAG_DATA, (void (CALLBACK*)()) _s_marshal_glu_t_callback_edgeFlag);
break;
}
}
@@ -719,23 +863,24 @@
GLdouble z
CODE:
{
- AV * data = 0;
- GLdouble v[3];
+ GLdouble *v = malloc(sizeof(GLdouble) * 3);
+ GLdouble *data = malloc(sizeof(GLdouble) * 7);
+ AV *vds = tess->vertex_datas;
+ if (!vds) croak("Missing vertex data storage");
+ av_push(vds, newSViv((int)v));
+ av_push(vds, newSViv((int)data));
v[0] = x;
v[1] = y;
v[2] = z;
-
- if (items > 4) {
- data = newAV();
- PackCallbackST(data, 4);
-
- if (!tess->vertex_datas)
- tess->vertex_datas = newAV();
-
- av_push(tess->vertex_datas, newRV_inc((SV*)data));
- SvREFCNT_dec(data);
- }
-
+ data[0] = x;
+ data[1] = y;
+ data[2] = z;
+ if (items > 4) {
+ if (items != 6 && items != 7) croak("Invalid r, g, b, a arguments
to gluTessVertex");
+ I32 i;
+ for (i = 4; i<items; i++)
+ data[i-1] = (GLdouble)SvNV(ST(i));
+ }
gluTessVertex(tess->triangulator, &v[0], (void*)data);
}
@@ -771,3 +916,4 @@
#endif
#endif /* End IN_POGL_GLU_XS */
+
_______________________________________________
Perldl mailing list
[email protected]
http://mailman.jach.hawaii.edu/mailman/listinfo/perldl