#include "procedures.h"
#include "functions.h"
#include "utils.h"
//#include "tools.h"
#include "../dpuser_utils.h"
#include "../dpuser.procs.h"
#include "../dpuser.yacchelper.h"
#include "functions/astrolib/astrolib.h"
#include "platform.h"
#include "dpstring.h"
#include "dpstringlist.h"

#ifdef HAS_PGPLOT
#include "cpgplot.h"
#ifdef HAS_DPPGPLOT
#include "cpg3d.h"
#endif /* HAS_DPPGPLOT */
#endif /* HAS_PGPLOT */

#ifdef WIN
#include <windows.h>
//#include <platform.h>
#else
#include <unistd.h>
#include <dlfcn.h>
#endif

#ifdef WIN
#pragma warning (disable: 4018) // disable warning for comparing signed and unsigned
#pragma warning (disable: 4996) // disable warning for deprecated POSIX name
#endif /* WIN */

int main_dpuser2c(char *fname);
int main_idl2c(char *fname);

//void re_fail(char *msg, unsigned char op);

extern int imexasize; // imexasize already defined in dpuser.pgplot.cpp
extern int ScriptInterrupt;
extern dpStringList script;
extern int silence;

// for PGPLOT-procedures
int pgi[20];
float pgf[20];
char cans1[256], cans2[256];
// END: for PGPLOT-procedures

std::vector<compiled_procedure> compiledprocedures;
//std::list<compiled_procedure> tempCompiledProcs;
//int tempCompiledProcedurePresent = 0;

int lookupUserProcedure(char *s) {
    dpint64 i;

    for (i = 0; i < userpronames.count(); i++) {
        if (userpronames[i] == s) return i;
    }
    return -1;
}

// resolve procedure-names
int pgWord(char *s) {
    int i;

   // built-in
    for (i = 0; i < npg; i++)
        if (procs[i].name == s) return i;

   // compiled
    for (i = 0; i < compiledprocedures.size(); i++) {
        if (compiledprocedures[i].name == s) return npg + i + 1;
    }

   // stored
    if ((i = lookupUserProcedure(s)) != -1) return -i-1;

    return -10000;
}

// resolve procedure-names for compile command
// return value of
//     zero means that procedure doesn't exist
//     -1 means that procedure is already builtin
//     -2 means that procedure is already stored
int pgWord_for_compile(const dpString &s) {
    int i;

    char *n = (char *)(s.c_str());

    // built-in procedure
    for (i = 0; i < npg; i++)
        if (procs[i].name == n) return -1;

    // stored procedure
    if ((i = lookupUserProcedure(n)) != -1) return -2;

    // compiled function
    for (i = 0; i < compiledfunctions.size(); i++) {
        if (compiledfunctions[i].name == s) return -3;
    }

    return 0;
}

// resolve procedure-names for store-procedure command
// return value of
//     zero means that procedure doesn't exist
//     -1 means that procedure is already builtin
//     -2 means that procedure is already copmpiled
int pgWord_for_store(const dpString &s)
{
    int i;
   char *n = (char *)(s.c_str());

   // built-in
    for (i = 0; i < npg; i++) {
        if (procs[i].name == n) return -1;
    }
   // compiled
    for (i = 0; i < compiledprocedures.size(); i++) {
        if (compiledprocedures[i].name == s) return -2;
    }

    return 0;
}

void execCompiledProcedure(dpString which, int nargs, dpuserType *args) {
    bool found = FALSE;
    int i, w;

    for (i = 0; i < compiledprocedures.size(); i++) {
        if (which == compiledprocedures[i].name) {
            w = i;
            if (nargs == compiledprocedures[i].nargs) found = TRUE;
        }
    }
    if (found) switch (nargs) {
        case 0: compiledprocedures[w].arg0(); break;
        case 1: compiledprocedures[w].arg1(args[0]); break;
        case 2: compiledprocedures[w].arg2(args[0],args[1]); break;
        case 3: compiledprocedures[w].arg3(args[0],args[1],args[2]); break;
        case 4: compiledprocedures[w].arg4(args[0],args[1],args[2],args[3]); break;
        case 5: compiledprocedures[w].arg5(args[0],args[1],args[2],args[3],args[4]); break;
        case 6: compiledprocedures[w].arg6(args[0],args[1],args[2],args[3],args[4],args[5]); break;
        case 7: compiledprocedures[w].arg7(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); break;
        case 8: compiledprocedures[w].arg8(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); break;
        case 9: compiledprocedures[w].arg9(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); break;
        case 10: compiledprocedures[w].arg10(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]); break;
        case 11: compiledprocedures[w].arg11(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]); break;
        case 12: compiledprocedures[w].arg12(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]); break;
        case 13: compiledprocedures[w].arg13(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]); break;
        case 14: compiledprocedures[w].arg14(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]); break;
        case 15: compiledprocedures[w].arg15(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14]); break;
        case 16: compiledprocedures[w].arg16(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15]); break;
        case 17: compiledprocedures[w].arg17(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15],args[16]); break;
        case 18: compiledprocedures[w].arg18(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15],args[16],args[17]); break;
        case 19: compiledprocedures[w].arg19(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15],args[16],args[17],args[18]); break;
        case 20: compiledprocedures[w].arg20(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13],args[14],args[15],args[16],args[17],args[18],args[19]); break;
        default: break;
    }
}
void dpuserProcedure_pgarro(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgarro", arg1, arg2, arg3, arg4);
    cpgarro(arg1.toDouble(), arg2.toDouble(), arg3.toDouble(), arg4.toDouble());
#endif
}

void dpuserProcedure_pgask(dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgask", arg1);
    cpgask(arg1.toInt());
#endif
}

//Alex
/*!
saomarkpoint
Draws a marker in ds9 at specified x,y coordinates with size s. (Use ds9 v5.2 or newer!)
Syntax
saomarkpoint x, y, size, type
Arguments
x: X-axes coordinate of the center of the circle
y: Y-axes coordinate of the center of the circle
size: The size of the marker to be drawn
type: Marker type, give one of the following (can be OR'ed)
POINT: 2
BOX: 4
DIAMOND: 32
CIRCLE: 64
See also
procedure_sao
procedure_saomarklabel
procedure_saoclear
*/

void dpuserProcedure_saomarkpoint(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("saomarkpoint", arg0, arg1, arg2, arg3);

    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (ds9_frame_loaded() == 0) {
        throw dpuserTypeException("ERROR: First load a fits-file into ds9 either in ds9 itself or with sao in dpuser!\n");
    }

    int ret = 0;
    char *names[NXPA];
    char *messages[NXPA];
    dpString pos = dpString::number(arg0.lvalue) + " " + dpString::number(arg1.lvalue);
    dpString cmd = "regions command { ";
    dpString accessPoint;

    if (arg3.lvalue & 2) {
        // point
        accessPoint = cmd + "point " + pos + " }";
    }
    if (arg3.lvalue & 4) {
        // box
        accessPoint =    cmd + "box " + pos + " " +
                        dpString::number(arg2.lvalue) + " " +
                        dpString::number(arg2.lvalue) + " }";
    }
    if (arg3.lvalue & 32) {
        // diamond
        accessPoint =    cmd + "box " + pos + " " +
                        dpString::number(arg2.lvalue) + " " +
                        dpString::number(arg2.lvalue) + " 45 }";
    }
    if (arg3.lvalue & 64) {
        // circle
        accessPoint =    cmd + "circle " + pos + " " +
                        dpString::number(arg2.lvalue / 2) + " }";
    }

    if ((arg3.lvalue & 2) || (arg3.lvalue & 4) ||
        (arg3.lvalue & 32) || (arg3.lvalue & 64)) {

        ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                    NULL, 0, names, messages, NXPA);

        /* error processing */
        for(int i = 0; i < ret; i++){
            if(messages[i]) {
                dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
            }
            if(names[i]) {
                free(names[i]);
            }
            if(messages[i]) {
                free(messages[i]);
            }
        }
    } else {
        dp_output("This marker type is not supported anymore!");
    }
}

//Alex
/*!
saoclear
Clear ds9 of all markers drawn.  (Use ds9 v5.2 or newer!)
Syntax
saoclear
See also
procedure_sao
procedure_saomarkpoint
procedure_saomarklabel
*/

void dpuserProcedure_saoclear() {
    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (ds9_frame_loaded() == 0) {
        throw dpuserTypeException("ERROR: First load a fits-file into ds9 either in ds9 itself or with sao in dpuser!\n");
    }
    int ret;
    char *names[NXPA];
    char *messages[NXPA];
    ret = XPASet(xpa, xpaServer, "regions delete all", NULL,
                 NULL, 0, names, messages, NXPA);

    /* error processing */
    for(int i = 0; i < ret; i++){
        if(messages[i]) {
            dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
        }
        if(names[i]) {
            free(names[i]);
        }
        if(messages[i]) {
            free(messages[i]);
        }
    }
}

//Alex
/*!
saomarklabel
Draws a text label in ds9 at specified x,y coordinates. (Use ds9 v5.2 or newer!)
Syntax
saomarklabel x, y, label
Arguments
x: X-axes coordinate of the center of the circle
y: Y-axes coordinate of the center of the circle
label: A string to be printed next to the marker
See also
procedure_sao
procedure_saomarkpoint
procedure_saoclear
*/

void dpuserProcedure_saomarklabel(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("saomarklabel", arg0, arg1, arg2);

    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (ds9_frame_loaded() == 0) {
        throw dpuserTypeException("ERROR: First load a fits-file into ds9 either in ds9 itself or with sao in dpuser!\n");
    }

    int ret;
    char *names[NXPA];
    char *messages[NXPA];

    dpString accessPoint =    "regions command { text " +
                            dpString::number(arg0.lvalue) + " " +
                            dpString::number(arg1.lvalue) + " \"" +
                            *(arg2.svalue) + "\" }";

    ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                 NULL, 0, names, messages, NXPA);

    /* error processing */
    for(int i = 0; i < ret; i++){
        if(messages[i]) {
            dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
        }
        if(names[i]) {
            free(names[i]);
        }
        if(messages[i]) {
            free(messages[i]);
        }
    }
}

#ifdef HAS_PGPLOT

//Alex
/*!
imexa
Display X in ds9. Interactively, the following can be done pressing keys in the viewer:
key  action
 c   contour plot
 s   isosurface
 h   horizontal cut
 v   vertical cut
 r   radial average
 i   increase window size
 d   decrease window size
 q   quit and return to dpuser
(Use ds9 v5.2 or newer!)
Syntax
imexa X
See also
procedure_sao
*/

void dpuserProcedure_imexa(dpuserType arg0) {
    checkProcArgs("imexa", arg0);

    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (xpa == NULL) {
        if ((xpa = XPAOpen(NULL)) == NULL) {
            throw dpuserTypeException("Can't open socket to image display server.");
        }
    }

    int nx, ny, x, y, ret, pos;
    dpString key, tmp;
    float *pix = NULL;
    size_t lens[NXPA];
    char *bufs[NXPA];
    char *names[NXPA];
    char *messages[NXPA];

    nx = arg0.fvalue->Naxis(1);
    ny = arg0.fvalue->Naxis(2);

    if ((pix = (float *)malloc(arg0.fvalue->Nelements() * sizeof(float))) == NULL)
        throw dpuserTypeException("Failed allocating memory");

    float *data1 = floatdata(*arg0.fvalue);
    if (data1) {
        memcpy(pix, data1, arg0.fvalue->Nelements() * sizeof(float));
    } else {
        free(pix);
        throw dpuserTypeException("Failed copying memory");
    }
    if (data1 && (data1 != arg0.fvalue->r4data))
        free(data1);

    // display fits
    dpString accessPoint = "array [xdim=" + dpString::number(nx) +
                           ",ydim=" + dpString::number(ny) +
                           ",bitpix=-32]";

    ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                 (char*)pix, nx * ny * (abs(arg0.fvalue->membits) / 8),
                 names, messages, NXPA);

    /* error processing */
    for(int i = 0; i < ret; i++){
        if(messages[i]) {
            dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
        }
        if(names[i]) {
            free(names[i]);
        }
        if(messages[i]) {
            free(messages[i]);
        }
    }

    dpString sp = dpString(" ");
    key = "t";
    try {
        while ((key.compare("q")) && (xpa != NULL)) {
            ret = XPAGet(xpa, xpaServer, "imexam key coordinate image", NULL,
                         bufs, lens, names, messages, NXPA);

            if( messages[0] == NULL ){
                /* extract key and x/y-positions */
                tmp = bufs[0];
                tmp = tmp.stripWhiteSpace();
                pos = tmp.strpos(sp, false);
                key = tmp.left(pos);
                tmp.remove(0,pos);
                tmp = tmp.stripWhiteSpace();
                x = atoi(tmp.left(tmp.strpos(sp, false)).c_str());
                y = atoi(tmp.right(tmp.length() - tmp.strpos(sp, false)).c_str());
                free(bufs[0]);

                if (key != "q") {
                    if ((key == "c") || (key == "s")) {
                            int i, j, ii, jj;
                            Fits *data = CreateFits();

                            if (data->create(imexasize*2+1, imexasize*2+1)) {
                                for (i = x-imexasize, ii = 1; i <= x+imexasize; i++, ii++) {
                                    for (j = y-imexasize, jj = 1; j <= y+imexasize; j++, jj++) {
                                        if ((i > 0) && (i <= nx) && (j > 0) && (j <= ny)) {
                                            data->r4data[data->F_I(ii, jj)] = arg0.fvalue->ValueAt((i-1) + (j-1)*nx);
                                        } else {
                                            data->r4data[data->F_I(ii, jj)] = 0.0;
                                        }
                                    }
                                }
                            }
                            if (key == "s") {
#ifdef HAS_DPPGPLOT
                                surface(data, 30.0, 1);
#endif /* HAS_DPPGPLOT */
                            } else if (key == "c") {
                                Fits *levels = CreateFits();
                                levels->create(9, 1);
                                for (i = 1; i < 10; i++) {
                                    levels->setValue(i * 10.0, i, 1);
                                }
                                contour(data, levels);
                            }
                    } else if (key == "h") {
                            Fits *data = CreateFits();
                            int i, ii;

                            if (data->create(imexasize*2+1, 1)) {
                                for (i = x-imexasize, ii = 1; i <= x+imexasize; i++, ii++) {
                                    if ((i > 0) && (i <= nx)) {
                                        data->r4data[data->F_I(ii, 1)] = arg0.fvalue->ValueAt((i-1) + (y-1)*nx);
                                    } else {
                                        data->r4data[data->F_I(ii, 1)] = 0.0;
                                    }
                                }
                                plot(NULL, data, 0.0, 0.0, 0, 0);
                            }
                    } else if (key == "v") {
                            Fits *data = CreateFits();
                            int i, ii;

                            if (data->create(imexasize*2+1, 1)) {
                                for (i = y-imexasize, ii = 1; i <= y+imexasize; i++, ii++) {
                                    if ((i > 0) && (i <= ny)) {
                                        data->r4data[data->F_I(ii, 1)] = arg0.fvalue->ValueAt((x-1) + (i-1)*nx);
                                    } else {
                                        data->r4data[data->F_I(ii, 1)] = 0.0;
                                    }
                                }
                                plot(NULL, data, 0.0, 0.0, 0, 0);
                            }
                    } else if (key == "i") {
                        if (imexasize < nx/2)
                            imexasize++;
                    } else if (key == "d") {
                        if (imexasize > 1)
                            imexasize--;
                    } else if (key == "r") {
                        radialplot(arg0.fvalue, x, y, imexasize, 5);
                    }
                }
                dp_output("%s [%d %d]\n", key.c_str(), x, y);
            }
            else{
                /* error processing */
                dp_output("ERROR: %s (%s)\n", messages[0], names[0]);
            }
            if(names[0])
                free(names[0]);
            if(messages[0])
                free(messages[0]);
        }
    } catch (std::exception &e) {
        e;    // prevent warning in VS
        dp_output("Lost connection to ds9.\n");
        XPAClose(xpa);
        xpa = NULL;
    }
}

#endif /* HAS_PGPLOT */

#if 0
void dpuserProcedure_pgaxis(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4,
            dpuserType arg5, dpuserType arg6, dpuserType arg7,
            dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11,
            dpuserType arg12, dpuserType arg13, dpuserType arg14) {
#ifndef HAS_PGPLOT
                throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgaxis", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
    cpgaxis(arg1.toString().c_str(),
            arg2.toDouble(),
            arg3.toFloat(),
            arg4.toFloat(),
            arg5.toFloat(),
            arg6.toFloat(),
            arg7.toFloat(),
            arg8.toFloat(),
            arg9.toInt(),
            arg10.toFloat(),
            arg11.toFloat(),
            arg12.toFloat(),
            arg13.toFloat(),
            arg14.toFloat());
#endif
}

void dpuserProcedure_pgbbuf(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgbbuf();
#endif
}

void dpuserProcedure_pgbeg(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgbeg", arg1, arg2, arg3, arg4);
    cpgbeg(arg1.toInt(), arg2.toString().c_str(), arg3.toInt(), arg4.toInt());
#endif
}

void dpuserProcedure_pgbegin(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgbegin", arg1, arg2, arg3, arg4);
    cpgbeg(arg1.toInt(), arg2.toString().c_str(), arg3.toInt(), arg4.toInt());
#endif
}

void dpuserProcedure_pgbin(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgbin", arg1, arg2, arg3, arg4);
    float *data1 = floatdata(*arg2.fvalue);
    float *data2 = floatdata(*arg3.fvalue);
    if (data1 && data2)
        cpgbin(arg1.toInt(), data1, data2, arg4.toInt());
    if (data1 && (data1 != arg2.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg3.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgbox(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgbox", arg1, arg2, arg3, arg4, arg5, arg6);
    cpgbox(arg1.toString().c_str(), arg2.toFloat(), arg3.toInt(), arg4.toString().c_str(), arg5.toFloat(), arg6.toInt());
#endif
}

void dpuserProcedure_pgcirc(dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgcirc", arg1, arg2, arg3);
    cpgcirc(arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgclos(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgclos();
#endif
}

void dpuserProcedure_pgconb(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgconb", arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);

    if ((arg2.toInt() > arg1.fvalue->Naxis(1)) || (arg3.toInt() > arg1.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgconb: Args 2 and 3 don't match given array");
    }
    if (abs(arg9.toInt()) > (long)arg8.fvalue->Nelements()) {
        throw dpuserTypeException("pgconb: Args 8 and 9 don't match");
    }
    if (arg10.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgconb: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg8.fvalue);
    float *data3 = floatdata(*arg10.fvalue);
    if (data1 && data2 && data3)
    cpgconb(data1, arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toInt(), data2, arg9.toInt(), data3, arg11.toFloat());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg8.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg10.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgconf(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgconf", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgconf: Args 2 and 3 don't match given array");
    }
    if (arg9.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgconf: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg9.fvalue);
    if (data1 && data2)
        cpgconf(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toFloat(), arg8.toFloat(), data2);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg9.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgconl(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgconl", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgconl: Args 2 and 3 don't match given array");
    }
    if (arg8.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgconl: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg8.fvalue);
    if (data1 && data2)
        cpgconl(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toFloat(), data2, arg9.svalue->c_str(), arg10.toInt(), arg11.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg8.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgcons(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgcons", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgcons: Args 2 and 3 don't match given array");
    }
    if (abs(arg8.toInt()) > (long)arg7.fvalue->Nelements()) {
        throw dpuserTypeException("pgcons: Args 8 and 9 don't match");
    }
    if (arg9.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgcons: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg7.fvalue);
    float *data3 = floatdata(*arg9.fvalue);
    if (data1 && data2 && data3)
        cpgcons(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), data2, arg8.toInt(), data3);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg7.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg9.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgcont(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgcont", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgcont: Args 2 and 3 don't match given array");
    }
    if (abs(arg8.toInt()) > (long)arg7.fvalue->Nelements()) {
        throw dpuserTypeException("pgcont: Args 8 and 9 don't match");
    }
    if (arg9.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgcont: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg7.fvalue);
    float *data3 = floatdata(*arg9.fvalue);
    if (data1 && data2 && data3)
        cpgcont(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), data2, arg8.toInt(), data3);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg7.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg9.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgctab(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgctab", arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    if ((arg5.toInt() > (long)arg1.fvalue->Nelements()) ||
            (arg5.toInt() > (long)arg2.fvalue->Nelements()) ||
            (arg5.toInt() > (long)arg3.fvalue->Nelements()) ||
            (arg5.toInt() > (long)arg4.fvalue->Nelements())) {
        throw dpuserTypeException("pgctab: Inconsistent number of color entries");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    float *data3 = floatdata(*arg3.fvalue);
    float *data4 = floatdata(*arg4.fvalue);
    if (data1 && data2 && data3 && data4)
        cpgctab(data1, data2, data3, data4, arg5.toInt(), arg6.toFloat(), arg7.toFloat());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg3.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg4.fvalue->r4data)) free(data4);
#endif
}

void dpuserProcedure_pgdraw(dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgdraw", arg1, arg2);
    cpgdraw(arg1.toFloat(), arg2.toFloat());
#endif
}

void dpuserProcedure_pgebuf(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgebuf();
#endif
}

void dpuserProcedure_pgend(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgend();
#endif
}

void dpuserProcedure_pgenv(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgenv", arg0, arg1, arg2, arg3, arg4, arg5);
    cpgenv(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toInt(), arg5.toInt());
#endif
}

void dpuserProcedure_pgeras(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgeras();
#endif
}

void dpuserProcedure_pgerr1(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgerr1", arg0, arg1, arg2, arg3, arg4);
    cpgerr1(arg0.toInt(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toFloat());
#endif
}

void dpuserProcedure_pgerrb(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgerrb", arg0, arg1, arg2, arg3, arg4, arg5);
    if ((arg1.toInt() > (long)arg2.fvalue->Nelements()) ||
            (arg1.toInt() > (long)arg3.fvalue->Nelements()) ||
            (arg1.toInt() > (long)arg4.fvalue->Nelements())) {
        throw dpuserTypeException("pgerrb: Inconsistent number of array elements");
    }
    float *data1 = floatdata(*arg2.fvalue);
    float *data2 = floatdata(*arg3.fvalue);
    float *data3 = floatdata(*arg4.fvalue);
    if (data1 && data2 && data3)
        cpgerrb(arg0.toInt(), arg1.toInt(), data1, data2, data3, arg5.toFloat());
    if (data1 && (data1 != arg2.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg3.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg4.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgerrx(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pgerrx", arg0, arg1, arg2, arg3, arg4);
    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) ||
            (arg0.toInt() > (long)arg2.fvalue->Nelements()) ||
            (arg0.toInt() > (long)arg3.fvalue->Nelements())) {
        throw dpuserTypeException("pgerrx: Inconsistent number of array elements");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    float *data3 = floatdata(*arg3.fvalue);
    if (data1 && data2 && data3)
        cpgerrx(arg0.toInt(), data1, data2, data3, arg4.toFloat());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg3.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgerry(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgerry", arg0, arg1, arg2, arg3, arg4);
    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) ||
            (arg0.toInt() > (long)arg2.fvalue->Nelements()) ||
            (arg0.toInt() > (long)arg3.fvalue->Nelements())) {
        throw dpuserTypeException("pgerry: Inconsistent number of array elements");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    float *data3 = floatdata(*arg3.fvalue);
    if (data1 && data2 && data3)
        cpgerry(arg0.toInt(), data1, data2, data3, arg4.toFloat());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg3.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgetxt(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgetxt();
#endif
}

void dpuserProcedure_pggray(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pggray", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pggray: Dimensions don't match given array");
    }
    if (arg9.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pggray: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg9.fvalue);
    if (data1 && data2)
        cpggray(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toFloat(), arg8.toFloat(), data2);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg9.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pghi2d(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pghi2d", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pghi2d: Dimensions don't match given array");
    }
    if (arg4.toInt() <= arg3.toInt()) {
        throw dpuserTypeException("pghi2d: IX2 must be greater than IX1");
    }
    if (arg4.toInt() - arg3.toInt() + 1 > (long)arg7.fvalue->Nelements()) {
        throw dpuserTypeException("pghi2d: Number of elements of abscissae too small");
    }
    if (arg4.toInt() - arg3.toInt() + 1 > (long)arg9.fvalue->Nelements()) {
        throw dpuserTypeException("pghi2d: Work array too small");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg7.fvalue);
    float *data3 = floatdata(*arg11.fvalue);
    if (data1 && data2 && data3)
        cpghi2d(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), data2, arg8.toInt(), arg9.toFloat(), arg10.toInt(), data3);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg7.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg11.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pghist(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pghist", arg0, arg1, arg2, arg3, arg4, arg5);

    if (arg0.toInt() > (long)arg1.fvalue->Nelements()) {
        throw dpuserTypeException("pghist: Inconsistent number of array elements");
    }
    float *data1 = floatdata(*arg1.fvalue);
    if (data1)
        cpghist(arg0.toInt(), data1, arg2.toFloat(), arg3.toFloat(), arg4.toInt(), arg5.toInt());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
#endif
}

void dpuserProcedure_pgiden(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgiden();
#endif
}

void dpuserProcedure_pgimag(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgimag", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    if ((arg1.toInt() > arg0.fvalue->Naxis(1)) || (arg2.toInt() > arg0.fvalue->Naxis(2))) {
        throw dpuserTypeException("pgimag: Dimensions don't match given array");
    }
    if (arg9.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgimag: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg9.fvalue);
    if (data1 && data2)
        cpgimag(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toFloat(), arg8.toFloat(), data2);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg9.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pglabel(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pglabel", arg0, arg1, arg2);

    cpglab(arg0.toString().c_str(), arg1.toString().c_str(), arg2.toString().c_str());
#endif
}

void dpuserProcedure_pglab(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pglab", arg0, arg1, arg2);

    cpglab(arg0.toString().c_str(), arg1.toString().c_str(), arg2.toString().c_str());
#endif
}

void dpuserProcedure_pglcur(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pglcur", arg0, arg1, arg2, arg3);

    int npg = variables[arg1.toInt()].lvalue;

    variables[arg1.toInt()].fvalue->setType(R4);
    variables[arg3.toInt()].fvalue->setType(R4);
    cpglcur(arg0.toInt(), &npg, variables[arg2.toInt()].fvalue->r4data, variables[arg3.toInt()].fvalue->r4data);
    variables[arg1.toInt()].lvalue = npg;
#endif
}

void dpuserProcedure_pgldev(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgldev();
#endif
}

void dpuserProcedure_pglen(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pglen", arg0, arg1, arg2, arg3);

    float xl, yl;

    cpglen(arg0.toInt(), arg1.toString().c_str(), &xl, &yl);
    variables[arg2.toInt()].type = typeDbl;
    variables[arg2.toInt()].dvalue = (double)xl;
    variables[arg3.toInt()].type = typeDbl;
    variables[arg3.toInt()].dvalue = (double)yl;
#endif
}

void dpuserProcedure_pgline(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgline", arg0, arg1, arg2);

    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) || (arg0.toInt() > (long)arg2.fvalue->Nelements())) {
        throw dpuserTypeException("pgline: Inconsistent number of points");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    if (data1 && data2)
        cpgline(arg0.toInt(), data1, data2);
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgmove(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgmove", arg0, arg1);

    cpgmove(arg0.toFloat(), arg1.toFloat());
#endif
}

void dpuserProcedure_pgmtext(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgmtext", arg0, arg1, arg2, arg3, arg4);

    cpgmtxt(arg0.toString().c_str(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toString().c_str());
#endif
}

void dpuserProcedure_pgmtxt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgmtxt", arg0, arg1, arg2, arg3, arg4);

    cpgmtxt(arg0.toString().c_str(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toString().c_str());
#endif
}

void dpuserProcedure_pgncur(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgncur", arg0, arg1, arg2, arg3, arg4);

    int npg = variables[arg1.toInt()].lvalue;

    variables[arg2.toInt()].fvalue->setType(R4);
    variables[arg3.toInt()].fvalue->setType(R4);
    cpgncur(arg0.toInt(), &npg, variables[arg2.toInt()].fvalue->r4data, variables[arg3.toInt()].fvalue->r4data, arg4.toInt());
    variables[arg1.toInt()].lvalue = npg;
#endif
}

void dpuserProcedure_pgncurse(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgncurse", arg0, arg1, arg2, arg3, arg4);

    int npg = variables[arg1.toInt()].lvalue;

    variables[arg2.toInt()].fvalue->setType(R4);
    variables[arg3.toInt()].fvalue->setType(R4);
    cpgncur(arg0.toInt(), &npg, variables[arg2.toInt()].fvalue->r4data, variables[arg3.toInt()].fvalue->r4data, arg4.toInt());
    variables[arg1.toInt()].lvalue = npg;
#endif
}

void dpuserProcedure_pgnumb(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgnumb", arg0, arg1, arg2, arg3, arg4);

    int nc, i;
    char cans1[256];

    for (i = 0; i < 256; i++) cans1[i] = (char)0;
    nc = 256;
    cpgnumb(arg0.toInt(), arg1.toInt(), arg2.toInt(), cans1, &nc);
    variables[arg3.toInt()].type = typeStr;
    variables[arg3.toInt()].svalue = CreateString(cans1);
    variables[arg4.toInt()].type = typeCon;
    variables[arg4.toInt()].lvalue = (long)nc;
#endif
}

void dpuserProcedure_pgolin(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgolin", arg0, arg1, arg2, arg3, arg4);

    int npg = variables[arg1.toInt()].lvalue;

    variables[arg2.toInt()].fvalue->setType(R4);
    variables[arg3.toInt()].fvalue->setType(R4);
    cpgolin(arg0.toInt(), &npg, variables[arg2.toInt()].fvalue->r4data, variables[arg3.toInt()].fvalue->r4data, arg4.toInt());
    variables[arg1.toInt()].lvalue = npg;
#endif
}

void dpuserProcedure_pgopen(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgopen", arg0);

    cpgopen(arg0.toString().c_str());
#endif
}

void dpuserProcedure_pgpage(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgpage();
#endif
}

void dpuserProcedure_pgpanl(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpanl", arg0, arg1);

    cpgpanl(arg0.toInt(), arg1.toInt());
#endif
}

void dpuserProcedure_pgpaper(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpaper", arg0, arg1);

    cpgpap(arg0.toFloat(), arg1.toFloat());
#endif
}

void dpuserProcedure_pgpap(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpap", arg0, arg1);

    cpgpap(arg0.toFloat(), arg1.toFloat());
#endif
}

void dpuserProcedure_pgpixl(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpixl", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);

    int *ia, i;

    if ((ia = (int *)malloc(arg1.toInt() * arg2.toInt() * sizeof(int))) == NULL) {
        throw dpuserTypeException("pgpixl: Memory allocation error");
    }
    for (i = 0; i < arg1.toInt() * arg2.toInt(); i++) ia[i] = (int)(arg0.fvalue->ValueAt(i));
    cpgpixl(ia, arg1.toInt(), arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toFloat(), arg8.toFloat(), arg9.toFloat(), arg10.toFloat());
    free(ia);
#endif
}

void dpuserProcedure_pgpnts(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpnts", arg0, arg1, arg2, arg3, arg4);

    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) || (arg0.toInt() > (long)arg2.fvalue->Nelements())) {
        throw dpuserTypeException("pgpnts: Inconsistent number of points");
    }
    if (arg4.toInt() > (long)arg3.fvalue->Nelements()) {
        throw dpuserTypeException("pgpnts: Inconsistent number of symbols");
    }
    int *symbol, i;

    if ((symbol = (int *)malloc(arg4.toInt() * sizeof(int))) == NULL) {
        throw dpuserTypeException("pgpnts: Memory allocation error");
    }
    for (i = 0; i < arg4.toInt(); i++) symbol[i] = (int)(arg3.fvalue->ValueAt(i));
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    if (data1 && data2)
        cpgpnts(arg0.toInt(), data1, data2, symbol, arg4.toInt());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    free(symbol);
#endif
}

void dpuserProcedure_pgpoint(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpoint", arg0, arg1, arg2, arg3);

    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) || (arg0.toInt() > (long)arg2.fvalue->Nelements())) {
        throw dpuserTypeException("pgpoint: Inconsistent number of points");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    if (data1 && data2)
        cpgpt(arg0.toInt(), data1, data2, arg3.toInt());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgpoly(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpoly", arg0, arg1, arg2);

    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) || (arg0.toInt() > (long)arg2.fvalue->Nelements())) {
        throw dpuserTypeException("pgpoly: Inconsistent number of points");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    if (data1 && data2)
        cpgpoly(arg0.toInt(), data1, data2);
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgpt1(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgpt1", arg0, arg1, arg2);

    cpgpt1(arg0.toFloat(), arg1.toFloat(), arg2.toInt());
#endif
}

void dpuserProcedure_pgptext(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgptext", arg0, arg1, arg2, arg3, arg4);

    cpgptxt(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toString().c_str());
#endif
}

void dpuserProcedure_pgpt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pgpt", arg0, arg1, arg2, arg3);

    if ((arg0.toInt() > (long)arg1.fvalue->Nelements()) || (arg0.toInt() > (long)arg2.fvalue->Nelements())) {
        throw dpuserTypeException("pgpt: Inconsistent number of points");
    }
    float *data1 = floatdata(*arg1.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    if (data1 && data2)
        cpgpt(arg0.toInt(), data1, data2, arg3.toInt());
    if (data1 && (data1 != arg1.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
#endif
}

void dpuserProcedure_pgptxt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgptxt", arg0, arg1, arg2, arg3, arg4);

    cpgptxt(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toString().c_str());
#endif
}

void dpuserProcedure_pgrect(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgrect", arg0, arg1, arg2, arg3);

    cpgrect(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgsah(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsah", arg0, arg1, arg2);

    cpgsah(arg0.toInt(), arg1.toFloat(), arg2.toFloat());
#endif
}

void dpuserProcedure_pgsave(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgsave();
#endif
}

void dpuserProcedure_pgunsa(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgunsa();
#endif
}

void dpuserProcedure_pgscf(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgscf", arg0);

    cpgscf(arg0.toInt());
#endif
}

void dpuserProcedure_pgsch(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsch", arg0);

    cpgsch(arg0.toFloat());
#endif
}

void dpuserProcedure_pgsci(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsci", arg0);

    cpgsci(arg0.toInt());
#endif
}

void dpuserProcedure_pgscir(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgscir", arg0, arg1);

    cpgscir(arg0.toInt(), arg1.toInt());
#endif
}

void dpuserProcedure_pgsclp(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsclp", arg0);

    cpgsclp(arg0.toInt());
#endif
}

void dpuserProcedure_pgscr(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgscr", arg0, arg1, arg2, arg3);

    cpgscr(arg0.toInt(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgscrl(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgscrl", arg0, arg1);

    cpgscrl(arg0.toFloat(), arg1.toFloat());
#endif
}

void dpuserProcedure_pgscrn(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgscrn", arg0, arg1);

    int i;
    cpgscrn(arg0.toInt(), arg1.toString().c_str(), &i);
#endif
}

void dpuserProcedure_pgsfs(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsfs", arg0);

    cpgsfs(arg0.toInt());
#endif
}

void dpuserProcedure_pgshls(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgshls", arg0, arg1, arg2, arg3);

    cpgshls(arg0.toInt(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgshs(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgshs", arg0, arg1, arg2);

    cpgshs(arg0.toFloat(), arg1.toFloat(), arg2.toFloat());
#endif
}

void dpuserProcedure_pgsitf(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsits", arg0);

    cpgsitf(arg0.toInt());
#endif
}

void dpuserProcedure_pgslct(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgslct", arg0);

    cpgslct(arg0.toInt());
#endif
}

void dpuserProcedure_pgsls(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsls", arg0);

    cpgsls(arg0.toInt());
#endif
}

void dpuserProcedure_pgslw(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgslw", arg0);

    cpgslw(arg0.toInt());
#endif
}

void dpuserProcedure_pgstbg(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgstbg", arg0);

    cpgstbg(arg0.toInt());
#endif
}

void dpuserProcedure_pgsubp(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsubp", arg0, arg1);

    cpgsubp(arg0.toInt(), arg1.toInt());
#endif
}

void dpuserProcedure_pgsvp(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgsvp", arg0, arg1, arg2, arg3);

    cpgsvp(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgswin(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgswin", arg0, arg1, arg2, arg3);

    cpgswin(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgtbox(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgtbox", arg0, arg1, arg2, arg3, arg4, arg5);

    cpgtbox(arg0.toString().c_str(), arg1.toFloat(), arg2.toInt(), arg3.toString().c_str(), arg4.toFloat(), arg5.toInt());
#endif
}

void dpuserProcedure_pgtext(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgtext", arg0, arg1, arg2);

    cpgtext(arg0.toFloat(), arg1.toFloat(), arg2.toString().c_str());
#endif
}

void dpuserProcedure_pgtick(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgtick", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    cpgtick(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toFloat(), arg5.toFloat(), arg6.toFloat(), arg7.toFloat(), arg8.toFloat(), arg9.toString().c_str());
#endif
}

void dpuserProcedure_pgupdt(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgupdt();
#endif
}

void dpuserProcedure_pgvect(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgvect", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);

    if ((arg0.fvalue->Naxis(1) != arg1.fvalue->Naxis(1)) ||
        (arg0.fvalue->Naxis(2) != arg1.fvalue->Naxis(2)) ||
        (arg2.toInt() != arg0.fvalue->Naxis(1)) ||
        (arg2.toInt() != arg0.fvalue->Naxis(1))) {
        throw dpuserTypeException("pgvect: Inconsistent array sizes");
    }
    if (arg10.fvalue->Nelements() != 6) {
        throw dpuserTypeException("pgvect: Transformation matrix must have exactly 6 elements");
    }
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg10.fvalue);
    if (data1 && data2 && data3)
        cpgvect(data1, data2, arg2.toInt(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toInt(), arg7.toInt(), arg8.toFloat(), arg9.toInt(), data3, arg11.toFloat());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg10.fvalue->r4data)) free(data3);
#endif
}

void dpuserProcedure_pgvport(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgvport", arg0, arg1, arg2, arg3);

    cpgsvp(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgvsize(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgvsize", arg0, arg1, arg2, arg3);

    cpgvsiz(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgvsiz(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgvsiz", arg0, arg1, arg2, arg3);

    cpgvsiz(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgvstand(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgvstd();
#endif
}

void dpuserProcedure_pgvstd(void) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    cpgvstd();
#endif
}

void dpuserProcedure_pgwedg(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgwedg", arg0, arg1, arg2, arg3, arg4, arg5);

    cpgwedg(arg0.toString().c_str(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat(), arg4.toFloat(), arg5.toString().c_str());
#endif
}

void dpuserProcedure_pgwindow(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgwindow", arg0, arg1, arg2, arg3);

    cpgswin(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

void dpuserProcedure_pgwnad(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgwnad", arg0, arg1, arg2, arg3);

    cpgwnad(arg0.toFloat(), arg1.toFloat(), arg2.toFloat(), arg3.toFloat());
#endif
}

#endif

/*!
writefits
Writes the array X to disk as a FITS file with specified filename, optionally as an extension. If X is a Fits List, a multiple extension FITS file is written.
Syntax
writefits FILENAME, X [, /ext]
Arguments
FILENAME: A string
X: A matrix or a Fits List
Switches
/ext: If specified, the matrix is written as a FITS image extension. If the file FILENAME exists already, the extension is appended (in which case the original FITS file must not be compressed), else an empty primary HDU is written and the extension appended.
*/
void dpuserProcedure_writefits(dpuserType arg1, dpuserType arg2, dpString option) {
    checkProcArgs("writefits", arg1, arg2);
//TODO: copy code from procedures.cpp (somehow does not work)
    if (arg2.type == typeDpArr) {
        int i;
        if (arg2.dparrvalue->at(0)->type == typeFits) {
            arg2.dparrvalue->at(0)->fvalue->WriteFITS(arg1.svalue->c_str());
            for (i = 1; i < arg2.dparrvalue->size(); i++) {
                if (arg2.dparrvalue->at(i)->type == typeFits) {
                    arg2.dparrvalue->at(i)->fvalue->WriteFITSExtension(arg1.svalue->c_str());
                }
            }
        }
    } else {
        if (option == "ext") {
            arg2.fvalue->WriteFITSExtension(arg1.svalue->c_str());
        } else {
            arg2.fvalue->WriteFITS(arg1.svalue->c_str());
        }
    }
}

#if 0

/*!
contour
Draw a contour map of X. levels give the contour levels in percent of the maximum value.
Syntax
contour fits X, fits levels [,title=string] [,xtitle=string] [,ytitle=string]
*/

void dpuserProcedure_contour(dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("contour", arg1, arg2);
    contour(arg1.fvalue, arg2.fvalue);
#endif
}

/*!
display
Displays a grayscale image of X. If min and max are set, the display of the image is clipped at these values. An optional keyword method can have 3 values:
method = 0: linear scaling
method = 1: log scaling
method = 2: square root scaling
Syntax
display fits [, float min, float max]
*/

void dpuserProcedure_display(dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("display", arg1);
    graymap(arg1.fvalue, 0.0, 0.0, variables[6].lvalue);
#endif
}

void dpuserProcedure_display(dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("display", arg1, arg2, arg3);
    graymap(arg1.fvalue, arg2.toDouble(), arg3.toDouble(), variables[6].lvalue);
#endif
}

/*!
exec
Execute cmd (which is given as a character string). Control is returned to DPUSER when cmd is finished.
Syntax
exec cmd
Arguments
cmd: A string containing the command to be executed.
Examples
Do a directory listing:
<code>exec "dir"
See also
function_exec
*/

void dpuserProcedure_exec(dpuserType arg1) {
    checkProcArgs("exec", arg1);
    system(arg1.svalue->c_str());
}

/*!
sleep
Sleep for the specified amount of seconds.
Syntax
sleep seconds
Arguments
seconds: An integer number.
*/

void dpuserProcedure_sleep(dpuserType arg1) {
    checkProcArgs("sleep", arg1);
    if (arg1.toInt() > 0) {
#ifdef WIN
//        Sleep(arg1.toInt()*1000);
#else
        sleep(arg1.toInt());
#endif
    }
}

/*!
print
prints the argument. Depending on the argument, the following happens:
  integer, real number, complex number, string, string array: the value is printed.
  matrix: some statistics on the array are printed.
Syntax
print argument
*/

void dpuserProcedure_print(dpuserType arg) {
   dpuserProcedure_print(arg, "");
}

void dpuserProcedure_print(dpuserType arg, dpuserType option) {
    switch(arg.type) {
        case typeCon: dp_output("%li\n", arg.lvalue); return;
        case typeDbl: dp_output("%6g\n", arg.dvalue); return;
        case typeStr: dp_output("%s\n", arg.svalue->c_str()); return;
        case typeCom: dp_output("%s\n", FormatComplexQString(*arg.cvalue).c_str()); return;
        case typeStrarr: {
            dpint64 i;

            for (i = 0; i < arg.arrvalue->count(); i++) {
                dp_output("%s\n", (*arg.arrvalue)[i].c_str());
            }
        }
            return;
        case typeFitsFile:
            arg.type = typeFits;
            arg.fvalue = CreateFits();
            if (!arg.fvalue->ReadFITS(arg.ffvalue->c_str())) break;
        case typeFits: {
            double min, max, flux, avg, fx, fy, fz;
            int x, y, z;
            Fits *_tmp = arg.fvalue;

            if (_tmp == NULL) return;
            if (option.toString().size() == 0) {
            dp_output("*******************************************************\n");
            dp_output("             Statistics on full array:\n");
            dp_output("number of axes    : %li\n", _tmp->Naxis(0));
            if (_tmp->Naxis(0) == 3) {
                dp_output("array size        : %li x %li x %li\n", _tmp->Naxis(1), _tmp->Naxis(2), _tmp->Naxis(3));
            } else if (_tmp->Naxis(0) == 2) {
                dp_output("array size        : %li x %li\n", _tmp->Naxis(1), _tmp->Naxis(2));
            } else {
                dp_output("array size        : %li\n", _tmp->Naxis(1));
            }
            dp_output("bitpix            : %i\n", (int)_tmp->membits);
            dp_stat(*_tmp, &min, &max, &flux, &avg);
//            _tmp->makeStat(&min, &max, &flux, &avg);
            _tmp->min_pos(&x, &y, &z);
            if (_tmp->Naxis(0) == 3) {
                dp_output("minimum value     :%16g     at:%4i%5i%5i\n", min, x, y, z);
            } else if (_tmp->Naxis(0) == 2) {
                dp_output("minimum value     :%16g     at:%4i%5i\n", min, x, y);
            } else {
                dp_output("minimum value     :%16g     at:%4i\n", min, x);
            }
            _tmp->max_pos(&x, &y, &z);
            if (_tmp->Naxis(0) == 3) {
                dp_output("maximum value     :%16g     at:%4i%5i%5i\n", max, x, y, z);
            } else if (_tmp->Naxis(0) == 2) {
                dp_output("maximum value     :%16g     at:%4i%5i\n", max, x, y);
            } else {
                dp_output("maximum value     :%16g     at:%4i\n", max, x);
            }
            _tmp->centroid(&fx, &fy, &fz);
            if (_tmp->Naxis(0) == 3) {
                dp_output("centroid at       : %2.2f %2.2f %2.2f\n", fx, fy, fz);
            } else if (_tmp->Naxis(0) == 2) {
                dp_output("centroid at       : %2.2f %2.2f\n", fx, fy);
            } else {
                dp_output("centroid at       : %2.2f\n", fx);
            }
            dp_output("total   value     :%16g\n", flux);
            dp_output("number of pixels  :%16li\n", _tmp->Nelements());
            dp_output("mean    value     :%16g\n", avg);
            dp_output("*******************************************************\n");
            } else if (option.toString() == dpString("values")) {
                unsigned long n = 0;

                for (z = 1; z <= _tmp->Naxis(3); z++) {
                    for (y = 1; y <= _tmp->Naxis(2); y++) {
                        for (x = 1; x <= _tmp->Naxis(1); x++) {
                            dp_output("%6g\t", _tmp->ValueAt(n));
                            n++;
                        }
                        dp_output("\n");
                    }
                    dp_output("\n");
                }
            }

        }
        return;
        default: dp_output("Don't know how to print this type.\n");
            return;
    }
}

/*!
mem
Prints information on all local variables, user defined or compiled functions and procedures.
Syntax
mem
*/

void dpuserProcedure_mem(void) {
    mem();
}

/*!
shift
Shifts (and optionally wraps) X by specified values.
Syntax
shift X, xs, ys [, zs] [, /wrap]
Arguments
X: The array to be shifted
xs: Shift vector in the first dimension
ys: Shift vector in the second dimension
zs: Shift vector in the third dimension
Switches
wrap: Pixels shifted off the array will be wrapped to the opposite side.
Notes
If either shift vector is non-integer, a subpixel shift is applied and the array type changed to R4. Subpixel shift is only supported in 2 dimensions.
See also
function_shift
*/

void dpuserProcedure_shift(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpString option) {
    checkProcArgs("shift", arg1, arg2, arg3);

    bool fs = TRUE;

    if ((arg2.toDouble() == (double)(int)arg2.toDouble()) &&
        (arg3.toDouble() == (double)(int)arg3.toDouble())) fs = FALSE;
    if (fs) {
            int method = 0;
            if (option == "linear") method = 0;
            if (option == "fft") method = 1;
            if (option == "poly3") method = 3;
                variables[arg1.toInt()].fvalue->fshift(arg2.toDouble(), arg3.toDouble(), method);
    } else {
        int x, y;

        x = arg2.toInt();
        y = arg3.toInt();
        if (option == "wrap") variables[arg1.toInt()].fvalue->wrap(x, y, 0);
        else variables[arg1.toInt()].fvalue->ishift(x, y, 0);
    }
}

void dpuserProcedure_shift(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpString option) {
    checkProcArgs("shift", arg1, arg2, arg3, arg4);

    bool fs = TRUE;

    if ((arg2.toDouble() == (double)(int)arg3.toDouble()) &&
        (arg3.toDouble() == (double)(int)arg3.toDouble()) &&
        (arg4.toDouble() == (double)(int)arg4.toDouble())) fs = FALSE;

    if (fs) {
        variables[arg1.toInt()].fvalue->fshift(arg2.toDouble(), arg3.toDouble(), arg4.toInt());
    } else {
        int x, y, z = 0;

        x = arg2.toInt();
        y = arg3.toInt();
        z = arg4.toInt();
        if (option == "wrap") variables[arg1.toInt()].fvalue->wrap(x, y, z);
        else variables[arg1.toInt()].fvalue->ishift(x, y, z);
    }
}

/*!
center
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
center X
See also
function_center
*/

void dpuserProcedure_center(dpuserType arg1) {
    checkProcArgs("center", arg1);

    int x, y;

    variables[arg1.toInt()].fvalue->max_pos(&x, &y);
    variables[arg1.toInt()].fvalue->shift(variables[arg1.toInt()].fvalue->Naxis(1) / 2 + 1 - x, variables[arg1.toInt()].fvalue->Naxis(2) / 2 + 1 - y, 2);
}

/*!
centroid
Returns the centroid of X in the variables x, y, and z.
y and z are optional.
Syntax
centroid X, VARIABLE x [, VARIABLE y [, VARIABLE z]]
*/

void dpuserProcedure_centroid(dpuserType arg1, dpuserType arg2) {
    checkProcArgs("centroid", arg1, arg2);

    double x, y, z;

    arg1.fvalue->centroid(&x, &y, &z);
    variables[arg2.toInt()].type = typeDbl;
    variables[arg2.toInt()].dvalue = x;
}

void dpuserProcedure_centroid(dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("centroid", arg1, arg2, arg3);

    double x, y, z;

    arg1.fvalue->centroid(&x, &y, &z);
    variables[arg2.toInt()].type = typeDbl;
    variables[arg2.toInt()].dvalue = x;
    variables[arg3.toInt()].type = typeDbl;
    variables[arg3.toInt()].dvalue = y;
}

void dpuserProcedure_centroid(dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("centroid", arg1, arg2, arg3, arg4);

    double x, y, z;

    arg1.fvalue->centroid(&x, &y, &z);
    variables[arg2.toInt()].type = typeDbl;
    variables[arg2.toInt()].dvalue = x;
    variables[arg3.toInt()].type = typeDbl;
    variables[arg3.toInt()].dvalue = y;
    variables[arg4.toInt()].type = typeDbl;
    variables[arg4.toInt()].dvalue = z;
}

/*!
upper
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
upper X
See also
function_upper
*/

void dpuserProcedure_upper(dpuserType arg0) {
    checkProcArgs("upper", arg0);

    variables[arg0.toInt()].svalue = CreateString(variables[arg0.toInt()].svalue->upper());
}

/*!
lower
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
lower X
See also
function_lower
*/

void dpuserProcedure_lower(dpuserType arg0) {
    checkProcArgs("lower", arg0);

    variables[arg0.toInt()].svalue = CreateString(variables[arg0.toInt()].svalue->lower());
}

/*!
export
Export data to fname. If X is a stringarray, each string in the array is printed as a separate line. If X is a fits, all values are printed as floating point numbers, separated by a single whitespace (" "). In this case, optionally a precision can be given (default: 2 decimal places).
Syntax
export string fname, stringarray|fits X [, int precision]
*/

void dpuserProcedure_export(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("export", arg0, arg1);

    dpuserType arg2 = 2;

    dpuserProcedure_export(arg0, arg1, arg2);
}

void dpuserProcedure_export(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("export", arg0, arg1, arg2);

    FILE *fd;
    int i, j, k, n;
    dpint64 ii;
    char format[10];

    if ((fd = fopen(arg0.toString().c_str(), "w+b")) == NULL) {
        throw dpuserTypeException("export: Could not open file for writing");
    }
    if (arg1.type == typeStrarr) {
        for (ii = 0; ii < arg1.arrvalue->count(); ii++) {
            fprintf(fd, "%s\n", (*arg1.arrvalue)[ii].c_str());
        }
    } else if (arg1.type == typeFits) {
        n = arg2.toInt();
        sprintf(format, "%%.%if ", n);
        for (k = 0; k < arg1.fvalue->Naxis(3); k++) {
            for (j = 0; j < arg1.fvalue->Naxis(2); j++) {
                for (i = 0; i < arg1.fvalue->Naxis(1); i++) {
                    fprintf(fd, format, arg1.fvalue->ValueAt(arg1.fvalue->C_I(i, j, k)));
                }
                fprintf(fd, "\n");
            }
        }
    }
    fclose(fd);
}

/*!
replace
replaces all occurrences of the string s by the string r.
Syntax
replace string|stringarray where, string s, string r
*/

void dpuserProcedure_replace(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("replace", arg0, arg1, arg2);

    if (arg0.type == typeStr) {
        arg0.svalue->replace(dpRegExp(*arg1.svalue), *arg2.svalue);
    } else if (arg0.type == typeStrarr) {
        for (dpint64 n = 0; n < arg0.arrvalue->count(); n++) (*arg0.arrvalue)[n].replace(dpRegExp(*arg1.svalue), *arg2.svalue);
    } else {
        throw dpuserTypeException("replace: Error executing procedure");
    }
}

//Alex
/*!
rotate
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
rotate X, angle [, xcen, ycen]
See also
function_rotate
*/

void dpuserProcedure_rotate(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("rotate", arg0, arg1);

    variables[arg0.toInt()].fvalue->rotate(arg1.toDouble());
}

//Alex
void dpuserProcedure_rotate(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("rotate", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->rotate(arg1.toDouble(), arg2.toDouble());
}

//Alex
void dpuserProcedure_rotate(dpuserType arg0,dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("rotate", arg0, arg1, arg2, arg3);

    variables[arg0.toInt()].fvalue->rotate(arg1.toDouble(), arg2.toDouble(), arg3.toDouble());
}

//Alex
/*!
fft
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
fft X
See also
function_fft
*/

void dpuserProcedure_fft(dpuserType arg0) {
    checkProcArgs("fft", arg0);

    variables[arg0.toInt()].fvalue->fft();
}

//Alex
/*!
reass
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
reass X
See also
function_reass
*/

void dpuserProcedure_reass(dpuserType arg0) {
    checkProcArgs("reass", arg0);

    variables[arg0.toInt()].fvalue->reass();
}

//Alex
/*!
norm
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
norm X [, /unity, /total, /average]
See also
function_norm
*/

void dpuserProcedure_norm(dpuserType arg0, dpString option) {
    checkProcArgs("norm", arg0);

    if (option == "total")
        variables[arg0.toInt()].fvalue->norf(0);
    else if (option == "average")
        variables[arg0.toInt()].fvalue->norf(0);
    else
        variables[arg0.toInt()].fvalue->norm();

}

//Alex
/*!
clip
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
clip X, low, high [, value]
See also
function_clip
*/

void dpuserProcedure_clip(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("clip", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->clip(arg1.toDouble(), arg2.toDouble());
}

//Alex
void dpuserProcedure_clip(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("clip", arg0, arg1, arg2, arg3);

    variables[arg0.toInt()].fvalue->inclip(arg1.toDouble(), arg2.toDouble(), arg3.toDouble());
}

//Alex
/*!
smooth
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
smooth X, fwhm
See also
function_smooth
*/

void dpuserProcedure_smooth(dpuserType arg0, dpuserType arg1, dpString option) {
    checkProcArgs("smooth", arg0, arg1);

    if ((option == "z") && (variables[arg0.toInt()].fvalue->Naxis(3) > 1)) {
        variables[arg0.toInt()].fvalue->smooth1d(arg1.toDouble(), 3);
    } else if (option == "x") {
        variables[arg0.toInt()].fvalue->smooth1d(arg1.toDouble(), 1);
    } else if (option == "y") {
        variables[arg0.toInt()].fvalue->smooth1d(arg1.toDouble(), 2);
    } else {
    variables[arg0.toInt()].fvalue->smooth(arg1.toDouble());
    }
}

//Alex
/*!
boxcar
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
boxcar X, width [, /average, /minimum, /maximum, /median]
See also
function_boxcar
*/

void dpuserProcedure_boxcar(dpuserType arg0, dpuserType arg1, dpString option1, dpString option2) {
    checkProcArgs("boxcar", arg0, arg1);

    int method1 = 0, method2 = 0;

    if (option1 == "minimum") method1 = 1;
    else if (option1 == "maximum") method1 = 2;
    else if (option1 == "median") method1 = 3;

    if (option2 == "z") method2 = 1;
    else if (option2 == "x") method2 = 2;
    else if (option2 == "y") method2 = 3;

    Boxcar(*variables[arg0.toInt()].fvalue, arg1.toInt(), method1, method2);
}

void dpuserProcedure_3dexpand(dpuserType arg0) {
    checkProcArgs("3dexpand", arg0);

    expandCal3d(*variables[arg0.toInt()].fvalue);
}

//Alex
/*!
flip
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
flip X, axis
See also
function_flip
*/

void dpuserProcedure_flip(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("flip", arg0, arg1);

    variables[arg0.toInt()].fvalue->flip(arg1.toInt());
}

//Alex
/*!
enlarge
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
enlarge X, scale, method = 0
See also
function_enlarge
*/

void dpuserProcedure_enlarge(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("enlarge", arg0, arg1);

    variables[arg0.toInt()].fvalue->enlarge(arg1.toInt());
}

//Alex
void dpuserProcedure_enlarge(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("enlarge", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->enlarge(arg1.toInt(), arg2.toInt());
}

//Alex
/*!
resize
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
resize X, naxis1, naxis2, naxis3
See also
function_resize
*/

void dpuserProcedure_resize(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("resize", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->resize(arg1.toInt(), arg2.toInt());
}

//Alex
void dpuserProcedure_resize(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("resize", arg0, arg1, arg2, arg3);

    variables[arg0.toInt()].fvalue->resize(arg1.toInt(), arg2.toInt(), arg3.toInt());
}

//Alex
/*!
wien
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
wien X, PSF [, height]
See also
function_wien
*/

void dpuserProcedure_wien(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("wien", arg0, arg1);

    variables[arg0.toInt()].fvalue->wien(*arg1.fvalue);
}

//Alex
void dpuserProcedure_wien(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("wien", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->wien(*arg1.fvalue, arg2.toDouble());
}

//Alex
/*!
lucy
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
lucy X, PSF, niter [, threshold]
See also
function_lucy
*/

void dpuserProcedure_lucy(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("lucy", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->lucy(*arg1.fvalue, arg2.toInt());
}

//Alex
void dpuserProcedure_lucy(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("lucy", arg0, arg1, arg2, arg3);

    variables[arg0.toInt()].fvalue->lucy(*arg1.fvalue, arg2.toInt(), arg3.toDouble());
}

//Alex
/*!
3dnorm
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
3dnorm X
See also
function_3dnorm
*/

void dpuserProcedure_3dnorm(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("3dnorm", arg0, arg1);

    norm3d(*variables[arg0.toInt()].fvalue, arg1.svalue->c_str());
}

//Alex
/*!
correl
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
correl X, Y
See also
function_correl
*/

void dpuserProcedure_correl(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("correl", arg0, arg1);

    variables[arg0.toInt()].fvalue->correl(*arg1.fvalue);
}

//Alex
/*!
rebin
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
rebin X, x1, x2
See also
function_rebin
*/

void dpuserProcedure_rebin(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("rebin", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->rebin(arg1.toInt(), arg2.toInt());
}

#ifdef HAS_PGPLOT
//Alex
/*!
ssaplot
Plot ssa statistics. The first argument must be created with ssastat Optionally, a title can be given as second argument which will be printed above all plots.
Syntax
ssaplot fits X [, string title]
See also
function_ssastat
*/

void dpuserProcedure_ssaplot(dpuserType arg0) {
    checkProcArgs("ssaplot", arg0);

    // this shall be an invalid value, title will not be printed
    dpuserType str;
    str.type = typeCon;
    str.lvalue = 0;

    dpuserProcedure_ssaplot(arg0, str);
}

//Alex
void dpuserProcedure_ssaplot(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("ssaplot", arg0, arg1);

    Fits *data = arg0.fvalue;
    float min, max, d, *xaxis, *yaxis;
    int i, j;

    if(cpgbeg(0, variables[5].svalue->c_str(), 1, 4) != 1)
        return;

    xaxis = (float *)malloc(data->Naxis(2) * sizeof(float));
    yaxis = (float *)malloc(data->Naxis(2) * sizeof(float));
    for (i = 1; i <= data->Naxis(2); i++)
        xaxis[i - 1] = (float)i;
    for (i = 3; i <= 6; i++) {
        min = max = (float)data->ValueAt(data->F_I(i, 1));
        for (j = 1; j <= data->Naxis(2); j++) {
            d = (float)data->ValueAt(data->F_I(i, j));
            if (d < min) min = d;
            else if (d > max) max = d;
            yaxis[j - 1] = d;
        }
        cpgenv(1.0, (float)data->Naxis(2), min, max, 0, 0);
        switch (i) {
            case 3: cpglab("Image Number", "Minimum", "");
                if (arg1.type == typeStr) {
                    cpgsch(2.0);
                    cpgmtxt("T", 1, 0.5, 0.5, arg1.svalue->c_str());
                    cpgsch(1.0);
                }
                break;
            case 4: cpglab("Image Number", "Maximum", ""); break;
            case 5: cpglab("Image Number", "Flux", ""); break;
            case 6: cpglab("Image Number", "Seeing [Pixels]", ""); break;
            default: break;
        }
        cpgslw(3);
        cpgpt(data->Naxis(2), xaxis, yaxis, -1);
        cpgslw(1);
    }
    free(xaxis);
    free(yaxis);
}

//Alex
/*!
freddy
Draw an isometric plot of X.
Syntax
freddy fits X, int xsize, int ysize, float scale, float angle
*/

#ifdef HAS_DPPGPLOT
void dpuserProcedure_freddy(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("freddy", arg0, arg1, arg2, arg3, arg4);

    Fits *data;

    if (isVariable(arg0.fvalue) == 1) {
        data = CreateFits();
        if (!data->copy(*arg0.fvalue)) return;
    } else {
        data = arg0.fvalue;
    }
    if (!data->setType(R4)) return;
    cfreddy(data->r4data, arg1.toInt(), arg2.toInt(), arg3.toDouble(), arg4.toDouble());
}

//Alex
/*!
surface
Draw an isosurface of X. This is seen under the angle. If skip is specified and > 1, only every nth line is drawn.
Syntax
surface fits X, float angle [, int skip]
*/

void dpuserProcedure_surface(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("surface", arg0, arg1);

    surface(arg0.fvalue, arg1.toDouble(), 1);
}

//Alex
void dpuserProcedure_surface(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("surface", arg0, arg1, arg2);

    surface(arg0.fvalue, arg1.toDouble(), arg2.toInt());
}
#endif /* HAS_DPPGPLOT */

//Alex
/*!
sbfint
Initialises the software buffer for crystal-plotting. It should  be called just once per plot (buffer), after PGWINDOW but before any crystal-related routines.
Syntax
sbfint RGB,IC,IBMODE,IBUF,MAXBUF
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
RGB:      R*4    I       3      The RGB values for the background.
IC:       I*4    I       -      The index for the background colour.
IBMODE:   I*4    I       -      Buffering mode for initialisation:
                                 1 = Ordinary, default.
                                 2 = Will want to save later.
                                 3 = Initialise from saved buffers.
IBUF:     I*4    I       -      Software buffer to be used (>=1).
MAXBUF:   I*4    O       -      Maximum number of buffers available.
*/

#ifdef HAS_DPPGPLOT
void dpuserProcedure_sbfint(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("sbfint", arg0, arg1, arg2, arg3, arg4);

    int maxbuf;

    float *data1 = floatdata(*arg0.fvalue);
    if (data1)
        csbfint(data1, arg1.toInt(), arg2.toInt(), arg3.toInt(), &maxbuf);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    variables[arg4.toInt()].type = typeCon;
    variables[arg4.toInt()].lvalue = maxbuf;
}

//Alex
/*!
sbfbkg
Sets the shading for the background. This routine should be called after SBFINT, and COLINT or COLTAB, but before any objects are plotted.
Syntax
sbfbkg IC1,IC2,ISHADE
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
ISHADE:   I*4    I       -      Order of shading (IC1-->IC2 - IC1):
                                  1 - Bottom to top.
                                  2 - Left to right.
                                  3 - Bottom-left to top-right.
                                  4 - Top-left to bottom-right.
                                  5 - Bottom, middle and top.
                                  6 - Left, middle and right.
                                  7 - Rectangular zoom to centre.
                                  8 - Elliptical zoom to centre.
*/

void dpuserProcedure_sbfbkg(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("sbfbkg", arg0, arg1, arg2);

    csbfbkg(arg0.toInt(), arg1.toInt(), arg2.toInt());
}

//Alex
/*!
sbfsav
Save a rendered picture-buffer, and its Z-buffer, for subsequent use in re-initialisation with SBFINT.
Syntax
sbfsav IBUF
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
IBUF:     I*4    I       -      Software buffer to be saved (>=1).
*/

void dpuserProcedure_sbfsav(dpuserType arg0) {
    checkProcArgs("sbfsav", arg0);

    csbfsav(arg0.toInt());
}

//Alex
/*!
sbfcls
Closes the software buffer for crystal-plotting, by outputting it to the screen or writing out a postscript file (as appropriate).
Syntax
sbfcls IBUF
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
IBUF:     I*4    I       -      Software buffer to be output (>=1).
*/

void dpuserProcedure_sbfcls(dpuserType arg0) {
    checkProcArgs("sbfcls", arg0);

    csbfcls(arg0.toInt());
}

//Alex
/*!
colint
Initialises a colour table for a geometrical object. In general, it is recommended that SHINE = 0.0 if DIFUSE > 0.0 and vice versa.
Syntax
colint RGB,IC1,IC2,DIFUSE,SHINE,POLISH
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
RGB:      R*4    I       3      Red, green and blue intenisty for 
                                fully-lit non-shiny object (0-1).
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for shading.
DIFUSE:   R*4    I       -      Diffusiveness of object (0-1).
SHINE:    R*4    I       -      Whiteness of bright spot (0-1).
POLISH:   R*4    I       -      Controls size of bright spot.
*/

void dpuserProcedure_colint(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
    checkProcArgs("colint", arg0, arg1, arg2, arg3, arg4, arg5);

    float *data1 = floatdata(*arg0.fvalue);
    if (data1)
        ccolint(data1, arg1.toInt(), arg2.toInt(), arg3.toDouble(), arg4.toDouble(), arg5.toDouble());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
}

//Alex
/*!
coltab
Initialises a colour table for a "grey-scale" map.
Syntax
coltab RGB,NCOL,ALFA,IC1,IC2
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
RGB:      R*4    I   3 X NCOL   Red, green and blue intenisty for 
                                the colour table.
NCOL:     I*4    I       -      No. of colours in the input table.
ALFA:     R*4    I       -      Contrast-factor (linear=1).
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the output.
*/

void dpuserProcedure_coltab(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("coltab", arg0, arg1, arg2, arg3, arg4);

    float *data1 = floatdata(*arg0.fvalue);
    if (data1)
        ccoltab(data1, arg1.toInt(), arg2.toDouble(), arg3.toInt(), arg4.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
}

//Alex
/*!
colsrf
Initialises a colour table for a 3-D surface rendering of a 2-D array of "data".
Syntax
colsrf RGB,NCOL,ALFA,IC1,IC2,NCBAND,DIFUSE,SHINE,POLISH
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
RGB:      R*4    I   3 X NCOL   Red, green and blue intenisty for 
                                the colour table.
NCOL:     I*4    I       -      No. of colours in the input table.
ALFA:     R*4    I       -      Contrast-factor (linear=1).
IC1,IC2:  I*4    I       -      Lowest and highest colour-index to
                                be used for the rendering.
NCBAND:   I*4    I       -      Number of colour-bands for the
                                height, so that the number of shades
                                per band = (IC2-IC1+1)/NCBAND.
DIFUSE:   R*4    I       -      Diffusiveness of object (0-1).
SHINE:    R*4    I       -      Whiteness of bright spot (0-1).
POLISH:   R*4    I       -      Controls size of bright spot.
*/

void dpuserProcedure_colsrf(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8) {
    checkProcArgs("colsrf", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);

    float *data1 = floatdata(*arg0.fvalue);
    if (data1)
        ccolsrf(data1, arg1.toInt(), arg2.toDouble(), arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toDouble(), arg7.toDouble(), arg8.toDouble());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
}

//Alex
/*!
sbball
This subroutine plots a shiny or matt coloured ball. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the ball-centre should be negative (< -radius); the viewing-screen is fixed at z=0.
Syntax
sbball EYE,CENTRE,RADIUS,IC1,IC2,LIGHT,LSHINE,X0,Y0,R0
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
CENTRE:   R*4    I       3      (x,y,z) coordinate of ball-centre.
RADIUS:   R*4    I       -      Radius of ball.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny ball if .TRUE., else diffuse.
X0,Y0:    R*4    O       -      Centre of projected ball.
R0:       R*4    O       -      Average radius of projected ball.
*/

void dpuserProcedure_sbball(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
    checkProcArgs("sbball", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    float x0, y0, r0;

    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3)
        csbball(data1, data2, arg2.toDouble(), arg3.toInt(), arg4.toInt(), data3, arg6.toInt(), &x0, &y0, &r0);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg5.fvalue->r4data)) free(data3);
    variables[arg7.toInt()].type = typeDbl;
    variables[arg7.toInt()].dvalue = (double)x0;
    variables[arg8.toInt()].type = typeDbl;
    variables[arg8.toInt()].dvalue = (double)y0;
    variables[arg9.toInt()].type = typeDbl;
    variables[arg9.toInt()].dvalue = (double)r0;
}

//Alex
/*!
sbtbal
This subroutine plots a semi-transparent shiny or matt coloured ball. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the ball-centre should be negative (< -radius); the viewing-screen is fixed at z=0.
Syntax
sbtbal EYE,CENTRE,RADIUS,IC1,IC2,LIGHT,LSHINE,X0,Y0,R0,ITRANS
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
CENTRE:   R*4    I       3      (x,y,z) coordinate of ball-centre.
RADIUS:   R*4    I       -      Radius of ball.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny ball if .TRUE., else diffuse.
X0,Y0:    R*4    O       -      Centre of projected ball.
R0:       R*4    O       -      Average radius of projected ball.
ITRANS:   I*4    I       -      Level of transparency:
                                     1 = 25%; 2 = 50%; 3 = 75%.
*/

void dpuserProcedure_sbtbal(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10) {
    checkProcArgs("sbtbal", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
    float x0, y0, r0;

    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3)
        csbtbal(data1, data2, arg2.toDouble(), arg3.toInt(), arg4.toInt(), data3, arg6.toInt(), &x0, &y0, &r0, arg10.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg5.fvalue->r4data)) free(data3);
    variables[arg7.toInt()].type = typeDbl;
    variables[arg7.toInt()].dvalue = (double)x0;
    variables[arg8.toInt()].type = typeDbl;
    variables[arg8.toInt()].dvalue = (double)y0;
    variables[arg9.toInt()].type = typeDbl;
    variables[arg9.toInt()].dvalue = (double)r0;
}

//Alex
/*!
sbplan
This subroutine plots a diffusively-lit coloured plane; the user must ensure that all the verticies lie in a flat plane, and that the bounding polygon be convex (so that the angle at any vertex <= 180 degs). All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbplan EYE,NV,VERT,IC1,IC2,LIGHT
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
NV:       R*4    I       -      No. of verticies (>=3).
VERT:     R*4    I     3 x NV   (x,y,z) coordinate of verticies.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
*/

void dpuserProcedure_sbplan(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
    checkProcArgs("sbplan", arg0, arg1, arg2, arg3, arg4, arg5);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    float *data3 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3)
        csbplan(data1, arg1.toDouble(), data2, arg3.toInt(), arg4.toInt(), data3);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg5.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbplnt
This subroutine plots a diffusively-lit, semi-transparent, coloured plane; the use must ensure that all the verticies lie in a flat plane, and that the bounding polygon be convex (so that the angle at any vertex <= 180 degs). All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbplnt EYE,NV,VERT,IC1,IC2,LIGHT,ITRANS
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
NV:       R*4    I       -      No. of verticies (>=3).
VERT:     R*4    I     3 x NV   (x,y,z) coordinate of verticies.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
ITRANS:   I*4    I       -      Level of transparency:
                                     1 = 25%; 2 = 50%; 3 = 75%.
*/

void dpuserProcedure_sbplnt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
    checkProcArgs("sbplnt", arg0, arg1, arg2, arg3, arg4, arg5, arg6);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg2.fvalue);
    float *data3 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3)
        csbplnt(data1, arg1.toDouble(), data2, arg3.toInt(), arg4.toInt(), data3, arg6.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg2.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg5.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbrod
This subroutine plots a diffusively-shaded coloured rod. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the rod-ends should be negative (< -radius); the viewing-screen is fixed at z=0.
Syntax
sbrod EYE,END1,END2,RADIUS,IC1,IC2,LIGHT,NSIDES,LEND
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
END1:     R*4    I       3      (x,y,z) coordinate of rod-end 1.
END2:     R*4    I       3      (x,y,z) coordinate of rod-end 2.
RADIUS:   R*4    I       -      Radius of cylinderical rod.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
NSIDES:   I*4    I       -      The order of the polygon to be used
                                for the cross-section of the rod.
LEND:     L*1    I       -      If true, plot the end of the rod.
*/

void dpuserProcedure_sbrod(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8) {
    checkProcArgs("sbrod", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg2.fvalue);
    float *data4 = floatdata(*arg6.fvalue);
    if (data1 && data2 && data3 && data4)
        csbrod(data1, data2, data3, arg3.toDouble(), arg4.toInt(), arg5.toInt(), data4, arg7.toInt(), arg8.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg2.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg6.fvalue->r4data)) free(data4);
}

//Alex
/*!
sbcone
This subroutine plots a diffusively-shaded coloured right-angular cone. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the base and appex of the cone should be negative (< -radius); the viewing-screen is fixed at z=0.
Syntax
sbcone EYE,BASE,APEX,RADIUS,IC1,IC2,LIGHT,NSIDES
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
BASE:     R*4    I       3      (x,y,z) coordinate of the centre of
                                the base of the cone.
APEX:     R*4    I       3      (x,y,z) coordinate of the apex.
RADIUS:   R*4    I       -      Radius of the base of the cone.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
NSIDES:   I*4    I       -      The order of the polygon to be used
                                for the cross-section of the cone.
*/

void dpuserProcedure_sbcone(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7) {
    checkProcArgs("sbcone", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg2.fvalue);
    float *data4 = floatdata(*arg6.fvalue);
    if (data1 && data2 && data3 && data4)
        csbcone(data1, data2, data3, arg3.toDouble(), arg4.toInt(), arg5.toInt(), data4, arg7.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg2.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg6.fvalue->r4data)) free(data4);
}

//Alex
/*!
sbelip
This subroutine plots a shiny or matt coloured elliptical ball. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the ball-centre should be negative (< -radius); the viewing-screen is fixed at z=0.
Syntax
sbelip EYE,CENTRE,PAXES,IC1,IC2,LIGHT,LSHINE,ICLINE,ANGLIN,X0,Y0,R0
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
CENTRE:   R*4    I       3      (x,y,z) coordinate of ball-centre.
PAXES:    R*4    I     3 x 3    Principal axes of the elliposid.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny ball if .TRUE., else diffuse.
ICLINE:   I*4    I       -      If >=0, colour index for lines on
                                surface of ellipsoid.
ANGLIN:   R*4    I       -      Width of lines: +/- degs.
X0,Y0:    R*4    O       -      Centre of projected ball.
R0:       R*4    O       -      Average radius of projected ball.
*/

void dpuserProcedure_sbelip(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
    checkProcArgs("sbelip", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
    float x0, y0, r0;

    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg2.fvalue);
    float *data4 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3 && data4)
        csbelip(data1, data2, data3, arg3.toInt(), arg4.toInt(), data4, arg6.toInt(), arg7.toInt(), arg8.toDouble(), &x0, &y0, &r0);
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg2.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg5.fvalue->r4data)) free(data4);
    variables[arg9.toInt()].type = typeDbl;
    variables[arg9.toInt()].dvalue = (double)x0;
    variables[arg10.toInt()].type = typeDbl;
    variables[arg10.toInt()].dvalue = (double)y0;
    variables[arg11.toInt()].type = typeDbl;
    variables[arg11.toInt()].dvalue = (double)r0;
}

//Alex
/*!
sbline
This subroutine draws a straight line between two points. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive, while that of both the ends should be negative; the viewing-screen is fixed at z=0.
Syntax
sbline EYE,END1,END2,ICOL,LDASH
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
END1:     R*4    I       3      (x,y,z) coordinate of end-1.
END2:     R*4    I       3      (x,y,z) coordinate of end-2.
ICOL:     I*4    I       -      Colour-index for line.
LDASH:    L*1    I       -      Dashed line if .TRUE. (else cont.).
*/

void dpuserProcedure_sbline(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("sbline", arg0, arg1, arg2, arg3, arg4);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg2.fvalue);
    if (data1 && data2 && data3)
        csbline(data1, data2, data3, arg3.toInt(), arg4.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg2.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbtext
Write a text string in 3-d perspective. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of the text string should be negative; the viewing-screen is fixed at z=0.
Syntax
sbtext EYE,TEXT,ICOL,PIVOT,FJUST,ORIENT,SIZE
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
TEXT:     C*1    I       *      The text string to be written.
ICOL:     I*4    I       -      Colour index for text.
PIVOT:    R*4    I       3      (x,y,z) coordinate of pivot point.
FJUST:    R*4    I       -      Position of pivot along the text: 
                                0.0=left, 0.5=centre, 1.0=right.
ORIENT:   R*4    I     3 x 2    (x,y,z) for X-length and Y-height
                                directions of the text.
SIZE:     R*4    I       -      Height of the reference symbol "A".
*/

void dpuserProcedure_sbtext(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
    checkProcArgs("sbtext", arg0, arg1, arg2, arg3, arg4, arg5, arg6);
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg3.fvalue);
    float *data3 = floatdata(*arg5.fvalue);
    if (data1 && data2 && data3)
        csbtext(data1, arg1.svalue->c_str(), arg2.toInt(), data2, arg4.toDouble(), data3, arg6.toDouble());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg3.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg5.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbsurf
This subroutine plots an iso-surface through a unit-cell of density. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of all the lattice-vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbsurf EYE,LATICE,DENS,N1,N2,N3,DSURF,IC1,IC2,LIGHT,LSHINE
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
LATICE:   R*4    I     3 x 4    (x,y,z) coordinates of the origin
                                and the a, b & C lattice-vertices.
DENS:     R*4    I     (N1+1)   The density at regular points within
                     x (N2+1)   the unit cell, wrapped around so
                     x (N3+1)   that DENS(0,J,K)=DENS(N1,J,K) etc..
N1,N2,N3: I*4    I       -      The dimensions of the unit-cell grid.
DSURF:    R*4    I       -      Density for the iso-surface.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny surface if TRUE, else diffuse.
*/

void dpuserProcedure_sbsurf(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10) {
    checkProcArgs("sbsurf", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
    Fits *data;

    if (isVariable(arg2.fvalue) == 1) {
        data = CreateFits();
        if (!data->copy(*arg2.fvalue)) return;
    } else {
        data = arg2.fvalue;
    }
    if (!data->setType(R4)) return;
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg9.fvalue);
    if (data1 && data2 && data3)
        csbsurf(data1, data2, data->r4data, arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toDouble(), arg7.toInt(), arg8.toInt(), data3, arg10.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg9.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbtsur
This subroutine plots a semi-transparent iso-surface through a unit-cell of density. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of all the lattice-vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbtsur EYE,LATICE,DENS,N1,N2,N3,DSURF,IC1,IC2,LIGHT,LSHINE,ITRANS
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
LATICE:   R*4    I     3 x 4    (x,y,z) coordinates of the origin
                                and the a, b & C lattice-vertices.
DENS:     R*4    I     (N1+1)   The density at regular points within
                     x (N2+1)   the unit cell, wrapped around so
                     x (N3+1)   that DENS(0,J,K)=DENS(N1,J,K) etc..
N1,N2,N3: I*4    I       -      The dimensions of the unit-cell grid.
DSURF:    R*4    I       -      Density for the iso-surface.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny surface if TRUE, else diffuse.
ITRANS:   I*4    I       -      Level of transparency:
                                     1 = 25%; 2 = 50%; 3 = 75%.
*/

void dpuserProcedure_sbtsur(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11) {
    checkProcArgs("sbtsur", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);

    Fits *data;

    if (isVariable(arg2.fvalue) == 1) {
        data = CreateFits();
        if (!data->copy(*arg2.fvalue)) return;
    } else {
        data = arg2.fvalue;
    }
    if (!data->setType(R4)) return;
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg9.fvalue);
    if (data1 && data2 && data3)
        csbtsur(data1, data2, data->r4data, arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toDouble(), arg7.toInt(), arg8.toInt(), data3, arg10.toInt(), arg11.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg9.fvalue->r4data)) free(data3);
}

//Alex
/*!
sbslic
This subroutine plots a "grey-scale" slice through a unit-cell of density. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of all the lattice-vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbslic EYE,LATICE,DENS,N1,N2,N3,DLOW,DHIGH,IC1,IC2,SLNORM,APOINT,ICEDGE
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
LATICE:   R*4    I     3 x 4    (x,y,z) coordinates of the origin
                                and the a, b & C lattice-vertices.
DENS:     R*4    I     (N1+1)   The density at regular points within
                     x (N2+1)   the unit cell, wrapped around so
                     x (N3+1)   that DENS(0,J,K)=DENS(N1,J,K) etc..
N1,N2,N3: I*4    I       -      The dimensions of the unit-cell grid.
DLOW:     R*4    I       -      Density for the lowest colour-index.
DHIGH:    R*4    I       -      Density for the highest colour-index.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
SLNORM:   R*4    I       3      (x,y,z) direction of the normal to 
                                the slice to be "grey-scaled".
APONIT:   R*4    I       3      (x,y,z) coordinate of a point within
                                the slice to be "grey-scaled".
ICEDGE:   I*4    I       -      If >=0, it's the colour-index for the
                                boundary of the "grey-scaled" slice.
*/

void dpuserProcedure_sbslic(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11, dpuserType arg12) {
    checkProcArgs("sbslic", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);

    Fits *data;

    if (isVariable(arg2.fvalue) == 1) {
        data = CreateFits();
        if (!data->copy(*arg2.fvalue)) return;
    } else {
        data = arg2.fvalue;
    }
    if (!data->setType(R4)) return;
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg10.fvalue);
    float *data4 = floatdata(*arg11.fvalue);
    if (data1 && data2 && data3 && data4)
        csbslic(data1, data2, data->r4data, arg3.toInt(), arg4.toInt(), arg5.toInt(), arg6.toDouble(), arg7.toDouble(), arg8.toInt(), arg9.toInt(), data3, data4, arg12.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg10.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg11.fvalue->r4data)) free(data4);
}

//Alex
/*!
sbcpln
This subroutine plots a diffusively-lit, semi-transparent, coloured plane through a unit cell. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of all the lattice-vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sbcpln EYE,LATICE,IC1,IC2,LIGHT,SLNORM,APOINT,ICEDGE,ITRANS
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
LATICE:   R*4    I     3 x 4    (x,y,z) coordinates of the origin
                                and the a, b & C lattice-vertices.
IC1,IC2:  I*4    I       -      Lowest & highest colour-index to be
                                used for the shading.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
SLNORM:   R*4    I       3      (x,y,z) direction of normal to plane.
APONIT:   R*4    I       3      (x,y,z) coordinate of a point within
                                the plane.
ICEDGE:   I*4    I       -      If >=0, it's the colour-index for
                                the boundary of the plane.
ITRANS:   I*4    I       -      Level of transparency:
                                  0 = 0%; 1 = 25%; 2 = 50%; 3 = 75%.
*/

void dpuserProcedure_sbcpln(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8) {
    checkProcArgs("sbcpln", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);

    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg4.fvalue);
    float *data4 = floatdata(*arg5.fvalue);
    float *data5 = floatdata(*arg6.fvalue);
    if (data1 && data2 && data3 && data4 && data5)
        csbcpln(data1, data2, arg2.toInt(), arg3.toInt(), data3, data4, data5, arg7.toInt(), arg8.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg4.fvalue->r4data)) free(data3);
    if (data4 && (data4 != arg5.fvalue->r4data)) free(data4);
    if (data5 && (data5 != arg6.fvalue->r4data)) free(data5);
}

//Alex
/*!
sb2srf
This subroutine plots a 3-d surface given a 2-d unit-cell of density. All (x,y,z) values are taken to be given in world coordinates. The z-component of the eye-poisition should be positive and that of all the lattice-vertices should be negative; the viewing-screen is fixed at z=0.
Syntax
sb2srf EYE,LATICE,DENS,N1,N2,DLOW,DHIGH,DVERT,IC1,IC2,NCBAND,LIGHT,LSHINE
Arguments
ARGUMENT  TYPE  I/O  DIMENSION  DESCRIPTION
EYE:      R*4    I       3      (x,y,z) coordinate of eye-position.
LATICE:   R*4    I     3 x 3    (x,y,z) coordinates of the origin
                                and the a and b lattice-vertices.
DENS:     R*4    I     (N1+1)   The density at regular points within
                     x (N2+1)   the unit cell, wrapped around so
                                that DENS(0,J)=DENS(N1,J) etc..
N1,N2:    I*4    I       -      The dimensions of the unit-cell grid.
DLOW:     R*4    I       -      Lowest density to be plotted.
DHIGH:    R*4    I       -      Highest density to be plotted.
DVERT:    R*4    I       -      "Vertical" world-coordinate length
                                corresponding to density-range.
IC1,IC2:  I*4    I       -      Lowest and highest colour-index to
                                be used for the rendering.
NCBAND:   I*4    I       -      Number of colour-bands for the
                                height, so that the number of shades
                                per band = (IC2-IC1+1)/NCBAND.
LIGHT:    R*4    I       3      (x,y,z) direction of flood-light.
LSHINE:   L*1    I       -      Shiny surface if TRUE, else diffuse.
*/

void dpuserProcedure_sb2srf(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9, dpuserType arg10, dpuserType arg11, dpuserType arg12) {
    checkProcArgs("sb2srf", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);

    Fits *data;

    if (isVariable(arg2.fvalue) == 1) {
        data = CreateFits();
        if (!data->copy(*arg2.fvalue)) return;
    } else {
        data = arg2.fvalue;
    }
    if (!data->setType(R4)) return;
    float *data1 = floatdata(*arg0.fvalue);
    float *data2 = floatdata(*arg1.fvalue);
    float *data3 = floatdata(*arg11.fvalue);
    if (data1 && data2 && data3)
        csb2srf(data1, data2, data->r4data, arg3.toInt(), arg4.toInt(), arg5.toDouble(), arg6.toDouble(), arg7.toDouble(), arg8.toInt(), arg9.toInt(), arg10.toInt(), data3, arg12.toInt());
    if (data1 && (data1 != arg0.fvalue->r4data)) free(data1);
    if (data2 && (data2 != arg1.fvalue->r4data)) free(data2);
    if (data3 && (data3 != arg11.fvalue->r4data)) free(data3);
}
#endif /* HAS_DPPGPLOT */

//Alex
/*!
radialplot
plots a radial average of x centered at [xcenter, ycenter] with a radius of r
Syntax
radialplot fits x, int xcenter, int ycenter, int r [,title=string] [,xtitle=string] [,ytitle=string]
*/

void dpuserProcedure_radialplot(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("radialplot", arg0, arg1, arg2, arg3);

    radialplot(arg0.fvalue, arg1.toInt(), arg2.toInt(), arg3.toInt(), 0);
}

#endif /* HAS_PGPLOT */

//Alex
/*!
setfitskey
add or change a FITS key in the header. value can be any of string, integer or double.
Syntax
setfitskey fits x, string key, value, string comment
See also
function_getfitskey
procedure_deletefitskey
*/

void dpuserProcedure_setfitskey(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("setfitskey", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->updateHeader();

    switch (arg2.type) {
        case typeCon: variables[arg0.toInt()].fvalue->SetIntKey(arg1.svalue->c_str(), arg2.toInt(), NULL);
            break;
        case typeDbl: variables[arg0.toInt()].fvalue->SetFloatKey(arg1.svalue->c_str(), arg2.toDouble(), NULL);
            break;
        case typeStr: variables[arg0.toInt()].fvalue->SetStringKey(arg1.svalue->c_str(), arg2.svalue->c_str(), NULL);
            break;
        default: break;
    }
}

//Alex
void dpuserProcedure_setfitskey(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("setfitskey", arg0, arg1, arg2, arg3);

    variables[arg0.toInt()].fvalue->updateHeader();

    char *comment = (char *)arg3.svalue->c_str();
    switch (arg2.type) {
        case typeCon: variables[arg0.toInt()].fvalue->SetIntKey(arg1.svalue->c_str(), arg2.toInt(), comment);
            break;
        case typeDbl: variables[arg0.toInt()].fvalue->SetFloatKey(arg1.svalue->c_str(), arg2.toDouble(), comment);
            break;
        case typeStr: variables[arg0.toInt()].fvalue->SetStringKey(arg1.svalue->c_str(), arg2.svalue->c_str(), comment);
            break;
        default: break;
    }
}

//Alex
/*!
setbitpix
Change pixel type of X.
Syntax
setbitpix fits x, int bitpix, double bscale = 1.0, double bzero = 0.0
See also
function_setbitpix
*/

void dpuserProcedure_setbitpix(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("setbitpix", arg0, arg1);

    if ((arg1.toInt() != 8) && (arg1.toInt() != 16) && (arg1.toInt() != 32) && (arg1.toInt() != -32) && (arg1.toInt() != -64) && (arg1.toInt() != -128)) {
        throw dpuserTypeException("setbitpix: Invalid bitpix.");
        return;
    }

    variables[arg0.toInt()].fvalue->setType((FitsBitpix)arg1.toInt());
}

//Alex
void dpuserProcedure_setbitpix(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("setbitpix", arg0, arg1, arg2);

    if ((arg1.toInt() != 8) && (arg1.toInt() != 16) && (arg1.toInt() != 32) && (arg1.toInt() != -32) && (arg1.toInt() != -64) && (arg1.toInt() != -128)) {
        throw dpuserTypeException("setbitpix: Invalid bitpix.");
        return;
    }

    variables[arg0.toInt()].fvalue->setType((FitsBitpix)arg1.toInt(), arg2.toDouble());
}

//Alex
void dpuserProcedure_setbitpix(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("setbitpix", arg0, arg1, arg2, arg3);

    if ((arg1.toInt() != 8) && (arg1.toInt() != 16) && (arg1.toInt() != 32) && (arg1.toInt() != -32) && (arg1.toInt() != -64) && (arg1.toInt() != -128)) {
        throw dpuserTypeException("setbitpix: Invalid bitpix.");
        return;
    }

    variables[arg0.toInt()].fvalue->setType((FitsBitpix)arg1.toInt(), arg2.toDouble(), arg3.toDouble());
}

//Alex
/*!
cd
change the current working directory.
Syntax
cd string
*/

void dpuserProcedure_cd(dpuserType arg0) {
    checkProcArgs("cd", arg0);

    char *dir = convertFileName(arg0.svalue->c_str());
    if (chdir(dir)) {
        dpString msg(arg0.svalue->c_str());
        msg += ": no such directory";
        throw dpuserTypeException( const_cast<char*>(msg.c_str()) );
        return;
    }
    free(dir);
}

//Alex
/*!
setwcs
set WCS information in the FITS header.
Syntax
setwcs fits, crpix1, crpix2, crval1, crval2, cdelt1 [, cdelt2]
*/

void dpuserProcedure_setwcs(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
    checkProcArgs("setwcs", arg0, arg1, arg2, arg3, arg4, arg5);

    variables[arg0.toInt()].fvalue->SetFloatKey("CRPIX1", arg1.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRPIX2", arg2.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRVAL1", arg3.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRVAL2", arg4.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CDELT1", arg5.toDouble());

    variables[arg0.toInt()].fvalue->SetFloatKey("CDELT2", arg5.toDouble());

//    variables[arg0.toInt()].fvalue->SetStringKey("CTYPE1", "LINEAR");
//    variables[arg0.toInt()].fvalue->SetStringKey("CTYPE2", "LINEAR");
}

//Alex
void dpuserProcedure_setwcs(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
    checkProcArgs("setwcs", arg0, arg1, arg2, arg3, arg4, arg5, arg6);

    variables[arg0.toInt()].fvalue->SetFloatKey("CRPIX1", arg1.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRPIX2", arg2.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRVAL1", arg3.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CRVAL2", arg4.toDouble());
    variables[arg0.toInt()].fvalue->SetFloatKey("CDELT1", arg5.toDouble());

    variables[arg0.toInt()].fvalue->SetFloatKey("CDELT2", arg6.toDouble());

//    variables[arg0.toInt()].fvalue->SetStringKey("CTYPE1", "LINEAR");
//    variables[arg0.toInt()].fvalue->SetStringKey("CTYPE2", "LINEAR");
}

//Alex
/*!
shrink
See documentation for the function of the same name. The reason to supply this also as a procedure is that it can be used without creating a temporary copy of the argument in memory. X must be a named variable.
Syntax
shrink X, factor [, axis]
See also
function_shrink
*/

void dpuserProcedure_shrink(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("shrink", arg0, arg1);

    variables[arg0.toInt()].fvalue->shrink(arg1.toInt());
}

void dpuserProcedure_shrink(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("shrink", arg0, arg1, arg2);

    variables[arg0.toInt()].fvalue->shrink(arg1.toInt(), arg2.toInt());
}

//Alex
/*!
view
Uses qtfitsview to display specified fits.
Syntax
view X
*/

void dpuserProcedure_view(dpuserType arg0) {
    checkProcArgs("view", arg0);

#ifdef DPQT
    // Notify QFitsView of variable change
    if (variables[arg0.toInt()].type == typeFits)
        dpUpdateVar(arg0.toInt());
#endif /* DPQT */
}

//Alex
/*!
limits
Returns the limits for which the array is non-zero in the given variables. At least xlow and xhigh must be given.
Syntax
limits fits, xlow, xhigh [, ylow, yhigh, zlow, zhigh]
*/

void dpuserProcedure_limits(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("limits", arg0, arg1, arg2);

    long x[6];

    arg0.fvalue->limits(&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);

    variables[arg1.toInt()].type = typeCon;
    variables[arg1.toInt()].lvalue = x[0];
    variables[arg2.toInt()].type = typeCon;
    variables[arg2.toInt()].lvalue = x[1];
}

//Alex
void dpuserProcedure_limits(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("limits", arg0, arg1, arg2, arg3);

    long x[6];

    arg0.fvalue->limits(&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);

    variables[arg1.toInt()].type = typeCon;
    variables[arg1.toInt()].lvalue = x[0];
    variables[arg2.toInt()].type = typeCon;
    variables[arg2.toInt()].lvalue = x[1];
    variables[arg3.toInt()].type = typeCon;
    variables[arg3.toInt()].lvalue = x[2];
}

//Alex
void dpuserProcedure_limits(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("limits", arg0, arg1, arg2, arg3, arg4);

    long x[6];

    arg0.fvalue->limits(&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);

    variables[arg1.toInt()].type = typeCon;
    variables[arg1.toInt()].lvalue = x[0];
    variables[arg2.toInt()].type = typeCon;
    variables[arg2.toInt()].lvalue = x[1];
    variables[arg3.toInt()].type = typeCon;
    variables[arg3.toInt()].lvalue = x[2];
    variables[arg4.toInt()].type = typeCon;
    variables[arg4.toInt()].lvalue = x[3];
}

//Alex
void dpuserProcedure_limits(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
    checkProcArgs("limits", arg0, arg1, arg2, arg3, arg4, arg5);

    long x[6];

    arg0.fvalue->limits(&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);

    variables[arg1.toInt()].type = typeCon;
    variables[arg1.toInt()].lvalue = x[0];
    variables[arg2.toInt()].type = typeCon;
    variables[arg2.toInt()].lvalue = x[1];
    variables[arg3.toInt()].type = typeCon;
    variables[arg3.toInt()].lvalue = x[2];
    variables[arg4.toInt()].type = typeCon;
    variables[arg4.toInt()].lvalue = x[3];
    variables[arg5.toInt()].type = typeCon;
    variables[arg5.toInt()].lvalue = x[4];
}

//Alex
void dpuserProcedure_limits(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
    checkProcArgs("limits", arg0, arg1, arg2, arg3, arg4, arg5, arg6);

    long x[6];

    arg0.fvalue->limits(&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]);

    variables[arg1.toInt()].type = typeCon;
    variables[arg1.toInt()].lvalue = x[0];
    variables[arg2.toInt()].type = typeCon;
    variables[arg2.toInt()].lvalue = x[1];
    variables[arg3.toInt()].type = typeCon;
    variables[arg3.toInt()].lvalue = x[2];
    variables[arg4.toInt()].type = typeCon;
    variables[arg4.toInt()].lvalue = x[3];
    variables[arg5.toInt()].type = typeCon;
    variables[arg5.toInt()].lvalue = x[4];
    variables[arg6.toInt()].type = typeCon;
    variables[arg6.toInt()].lvalue = x[5];
}

//Alex
/*!
printf
Print the value (either a real number or an integer) using specified format string. The formatting is done like in the C printf function. The total length of the formatted string is limited to 256 characters.
Syntax
printf format, value
*/

void dpuserProcedure_printf(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("printf", arg0, arg1);

    dpString out;

    if (arg1.type == typeCon)
        out.sprintf(arg0.svalue->c_str(), arg1.lvalue);
    else
        out.sprintf(arg0.svalue->c_str(), arg1.dvalue);

    dp_output("%s\n", out.c_str());
}

//Alex
/*!
writebmp
Write a bitmap (.bmp) file. If only red is given, this will be a grayscale image, else both green and blue must be given (which must be of the same size as red) and a color image will be written. The values in the fits are supposed to be scaled between 0 and 255.
Syntax
writebmp filename, red [, green, blue]
Arguments
filename: A string giving the file name of the bitmap
red: 2-dimensional array
green: A 2-dimensional array of the same size as red
blue: A 2-dimensional array of the same size as red
Examples
Write out a grayscale bitmap of a circular gaussian:
<code>writebmp "gauss.bmp", gauss(129,129,30)*255
*/

void dpuserProcedure_writebmp(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("writebmp", arg0, arg1);

    arg1.fvalue->WriteBMP(arg0.svalue->c_str());

}

//Alex
void dpuserProcedure_writebmp(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("writebmp", arg0, arg1, arg2);

    throw dpuserTypeException("writebmp: must be either one or three fits");
}

//Alex
void dpuserProcedure_writebmp(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("writebmp", arg0, arg1, arg2, arg3);

    Fits::WriteBMP(arg0.svalue->c_str(), *arg1.fvalue, *arg2.fvalue, *arg3.fvalue);
}

//Alex
/*!
swapbytes
Swap the bytes of given fits, which must be a variable.
Syntax
swapbytes fits
*/

void dpuserProcedure_swapbytes(dpuserType arg0) {
    checkProcArgs("swapbytes", arg0);

    unsigned long i;
    char tempr;
    char *_tmp;

    _tmp = (char *)arg0.fvalue->dataptr;
    if (arg0.fvalue->membits == C16) {
        for (i = 0; i < arg0.fvalue->Nelements() * 8 * 2; i += 8) {
            SWAP(_tmp[i], _tmp[i+7]);
            SWAP(_tmp[i+1], _tmp[i+6]);
            SWAP(_tmp[i+2], _tmp[i+5]);
            SWAP(_tmp[i+3], _tmp[i+4]);
        }
    } else if (arg0.fvalue->membits == T_R8) {
        for (i = 0; i < arg0.fvalue->Nelements() * 8; i += 8) {
            SWAP(_tmp[i], _tmp[i+7]);
            SWAP(_tmp[i+1], _tmp[i+6]);
            SWAP(_tmp[i+2], _tmp[i+5]);
            SWAP(_tmp[i+3], _tmp[i+4]);
        }
    } else if ((arg0.fvalue->membits == T_R4) || (arg0.fvalue->membits == T_I4)) {
        for (i = 0; i < arg0.fvalue->Nelements() * 4; i += 4) {
            SWAP(_tmp[i], _tmp[i+3]);
            SWAP(_tmp[i+1], _tmp[i+2]);
        }
    } else if (arg0.fvalue->membits == T_I2) {
        for (i = 0; i < arg0.fvalue->Nelements() * 2; i += 2) {
            SWAP(_tmp[i], _tmp[i+1]);
        }
    }
}

//Alex
/*!
read
Print prompt and read in up to 9 variables. The variables can be of integer, floating point or string type and must exist before the call.
Syntax
read prompt, v1 [, v2, v3, v4, v5, v6, v7, v8, v9]
*/

void dpuserProcedure_read(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("read", arg0, arg1);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("read", arg0, arg1, arg2);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("read", arg0, arg1, arg2, arg3);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4, arg5);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg5.toInt()].type) {
        case typeCon: variables[arg5.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg5.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg5.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4, arg5, arg6);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg5.toInt()].type) {
        case typeCon: variables[arg5.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg5.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg5.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg6.toInt()].type) {
        case typeCon: variables[arg6.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg6.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg6.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg5.toInt()].type) {
        case typeCon: variables[arg5.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg5.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg5.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg6.toInt()].type) {
        case typeCon: variables[arg6.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg6.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg6.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg7.toInt()].type) {
        case typeCon: variables[arg7.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg7.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg7.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg5.toInt()].type) {
        case typeCon: variables[arg5.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg5.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg5.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg6.toInt()].type) {
        case typeCon: variables[arg6.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg6.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg6.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg7.toInt()].type) {
        case typeCon: variables[arg7.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg7.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg7.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg8.toInt()].type) {
        case typeCon: variables[arg8.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg8.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg8.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
void dpuserProcedure_read(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7, dpuserType arg8, dpuserType arg9) {
    checkProcArgs("read", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);

    dp_output("%s", arg0.svalue->c_str());
    char *inp = (char *)malloc(256 * sizeof(char));

    read_inp(inp);
    switch (variables[arg1.toInt()].type) {
        case typeCon: variables[arg1.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg1.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg1.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg2.toInt()].type) {
        case typeCon: variables[arg2.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg2.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg2.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg3.toInt()].type) {
        case typeCon: variables[arg3.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg3.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg3.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg4.toInt()].type) {
        case typeCon: variables[arg4.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg4.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg4.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg5.toInt()].type) {
        case typeCon: variables[arg5.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg5.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg5.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg6.toInt()].type) {
        case typeCon: variables[arg6.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg6.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg6.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg7.toInt()].type) {
        case typeCon: variables[arg7.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg7.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg7.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg8.toInt()].type) {
        case typeCon: variables[arg8.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg8.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg8.toInt()].svalue = inp; break;
        default: break;
    }

    read_inp(inp);
    switch (variables[arg9.toInt()].type) {
        case typeCon: variables[arg9.toInt()].lvalue = atol(inp); break;
        case typeDbl: variables[arg9.toInt()].dvalue = atof(inp); break;
        case typeStr: *variables[arg9.toInt()].svalue = inp; break;
        default: break;
    }

    free(inp);
}

//Alex
/*!
shade
Plot an image in a variety of ways - as provided by PGXTAL. This procedure asks for plot options interactively. Possible plots are contour, shaded surface, and colour plots with various colourtables.
Syntax
shade fits
*/

void dpuserProcedure_shade(dpuserType arg0) {
    checkProcArgs("shade", arg0);

#ifdef HAS_PGPLOT
#ifdef HAS_DPPGPLOT
    shade(arg0.fvalue);
#endif /* HAS_DPPGPLOT */
#endif /* HAS_PGPLOT */
}

//Alex
/*!
cblank
Replace all undefined values (like NaN or Inf) by another value. If no value is specified, 0.0 will be replaced.
Syntax
cblank ARRAY [, value]
Arguments
ARRAY: A variable holding an array
value: Optional, the value to be assigned (defaults to 0)
See also
function_cblank
*/

void dpuserProcedure_cblank(dpuserType arg0) {
    checkProcArgs("cblank", arg0);

    variables[arg0.toInt()].fvalue->cblank();
}

//Alex
void dpuserProcedure_cblank(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("cblank", arg0, arg1);

    variables[arg0.toInt()].fvalue->cblank(arg1.toDouble());
}

//Alex
/*!
cubemerge
Merges several fits datacubes. All files must have the same array size (in the first two dimensions) and bitpix. The file name of the result must not be the same as any of the input names. The FITS header is copied from the first file and the NAXIS3 keyword is updated.
Syntax
cubemerge result, cubes
Arguments
result: The filename where the datacube is written to
cubes: A string array with the file names to be merged
*/

void dpuserProcedure_cubemerge(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("cubemerge", arg0, arg1);

    CubeMerge(arg0.svalue->c_str(), *arg1.arrvalue);
}

//Alex
/*!
setenv
Set or change an environment variable.
Syntax
setenv VARIABLE, VALUE
Arguments
VARIABLE: A string with the name of the new environment variable
VALUE: A string with the value of the new environment variable
See also
function_getenv
*/

void dpuserProcedure_setenv(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("setenv", arg0, arg1);

    dpString env;

    env = *arg0.svalue + "=" + *arg1.svalue;
    putenv(strdup(env.c_str()));
}

//Alex
/*!
break
Stop any currently running script or loop.
Syntax
break
Arguments
none
*/

void dpuserProcedure_break() {
    ScriptInterrupt = 1;
}

//Alex
/*!
run
Execute a script. This is equivalent to entering @script.
Syntax
run S
Arguments
S: A string with the file name of the script to be executed.
*/

void dpuserProcedure_run(dpuserType arg0) {
    checkProcArgs("run", arg0);

    FILE *fd;
    dpStringList inp;
    dpString fl;
    char *newinput;
    int irv, l, s;

    if ((fd = fopen(arg0.svalue->c_str(), "rb")) == NULL) {
        dpString msg("Could not open file ");
        msg += arg0.svalue->c_str();
        msg += " for reading\n";
        throw dpuserTypeException(const_cast<char*>(msg.c_str()));
        return;
    }
    if ((newinput = (char *)malloc(256 * sizeof(char))) == NULL) {
        fclose(fd);
        throw dpuserTypeException("run: Failed allocating memory.");
        return;
    }
    strcpy(newinput, "");
    irv = 0;
    while (irv != EOF) {
        l = s = 0;
        do {
            irv = fscanf(fd, "%c", &newinput[l++]);
            s++;
            if (s == 255) {
                if ((newinput = (char *)realloc(newinput, (l + 256) * sizeof(char))) == NULL) {
                    fclose(fd);
                    throw dpuserTypeException("run: Failed allocating memory.");
                    return;
                }
                s = 0;
            }
        } while ((newinput[l-1] != '\n') && (irv != EOF));
        l--;
        while (((newinput[l] == '\n') || (newinput[l] == '\r')) && (l > -1)) l--;
        newinput[l+1] = (char)0;
        if (irv != EOF) {
            inp.append(newinput);
            free(newinput);
            if ((newinput = (char *)malloc(256 * sizeof(char))) == NULL) {
                fclose(fd);
                throw dpuserTypeException("run: Failed allocating memory.");
                return;
            }
            strcpy(newinput, "");
            s = 0;
        }
    }
    fclose(fd);
    free(newinput);
    for (int i=inp.count() - 1; i >= 0; i--) {
        script.prepend(inp[i]);
    }
}

//Alex
/*!
echo
Turn on or off echo mode. Echo mode determines if external scripts are echoed to the console.
Syntax
echo mode
Arguments
mode: An integer number. 0 means echo off, any other number echo on.
*/

void dpuserProcedure_echo(dpuserType arg0) {
    checkProcArgs("echo", arg0);

    if (arg0.lvalue)
        silence = 0;
    else
        silence = 1;
}

//Alex
/*!
precess
Precess coordinates from one epoch to another.
Syntax
precess RAh, RAm, RAs, DECd, DECm, DECs, fromepoch, toepoch
Arguments
RAh, RAm, RAs: Right Ascension of the object
DECd, DECm, DECs: Declination of the object
fromepoch: Epoch in which the coordinates are given
toepoch: Epoch to which the coordinates should be precessed
*/

void dpuserProcedure_precess(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6, dpuserType arg7) {
    checkProcArgs("precess", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);

    precess(arg0.toDouble(), arg1.toDouble(), arg2.toDouble(), arg3.toDouble(), arg4.toDouble(), arg5.toDouble(), arg6.toDouble(), arg7.toDouble());
}

//Alex
/*!
pwd
Print current working directory
Syntax
pwd
Arguments
None
*/

void dpuserProcedure_pwd() {
    char *dir = convertFileNameReverse(dpDir::currentDirPath().c_str());
    dp_output("%s\n", dir);
    free(dir);
}

//Alex
/*!
dir
Print directory listing.
Syntax
dir [filter]
Arguments
filter: Print directory listing of files matching given pattern
*/

void dpuserProcedure_dir() {
   dpuserType rv;
   rv.type = typeStrarr;
   rv.arrvalue = CreateStringArray();

   *rv.arrvalue = dpDir::dir("*");

   for (int i = 0; i < (*rv.arrvalue).size(); i++) {
      dp_output("%s\n", (*rv.arrvalue)[i].c_str());
   }
}

//Alex
void dpuserProcedure_dir(dpuserType arg0) {
    checkProcArgs("dir", arg0);

   dpuserType rv;
   rv.type = typeStrarr;
   rv.arrvalue = CreateStringArray();

   *rv.arrvalue = dpDir::dir(*arg0.svalue);

   for (int i = 0; i < (*rv.arrvalue).size(); i++) {
      dp_output("%s\n", (*rv.arrvalue)[i].c_str());
   }
}

//Alex
void dpuserProcedure_newbuffer(dpuserType arg0) {
    checkProcArgs("newbuffer", arg0);

    int index;
    bool good;
    int extension = 0;
    dpString name = freeBufferName();
    index = createVariable((char *)name.c_str());

    variables[index].type = typeFits;
    variables[index].fvalue = CreateFits();

    if (extension < 1) {
        good = variables[index].fvalue->ReadFITS(arg0.svalue->c_str());
    } else {
        good = variables[index].fvalue->ReadFITSExtension(arg0.svalue->c_str(), extension);
    }
    if (good) {
    } else {
        svariables[index] = "";
        variables[index].fvalue = NULL;
    }

#ifdef DPQT
// Notify QFitsView of variable change
    if (good)
        dpUpdateVar(index);
#endif /* DPQT */
}

//Alex
void dpuserProcedure_newbuffer(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("newbuffer", arg0, arg1);

    int index;
    bool good;
    int extension = 0;
    dpString name = freeBufferName();
    index = createVariable((char *)name.c_str());

    extension = arg1.toInt();

    variables[index].type = typeFits;
    variables[index].fvalue = CreateFits();

    if (extension < 1) {
        good = variables[index].fvalue->ReadFITS(arg0.svalue->c_str());
    } else {
        good = variables[index].fvalue->ReadFITSExtension(arg0.svalue->c_str(), extension);
    }
    if (good) {
    } else {
        svariables[index] = "";
        variables[index].fvalue = NULL;
    }

#ifdef DPQT
// Notify QFitsView of variable change
    if (good)
        dpUpdateVar(index);
#endif /* DPQT */
}

//Alex
/*!
setindexbase
Set the base for array indexing
Syntax
setindexbase base
Arguments
base: The index base, 0 for C-notation, 1 for Fortran-notation (the default)
See also
procedure_cnotation
procedure_fortrannotation
function_indexbase
*/

void dpuserProcedure_setindexbase(dpuserType arg0) {
    checkProcArgs("setindexbase", arg0);

    indexBase = arg0.toInt();
}

//Alex
/*!
fortrannotation
Set the base for array indexing to 1 (the default for dpuser)
Syntax
fortrannotation
Arguments
none
See also
procedure_setindexbase
procedure_cnotation
function_indexbase
*/

void dpuserProcedure_fortrannotation() {

    indexBase = 1;
}

//Alex
/*!
cnotation
Set the base for array indexing to 0
Syntax
cnotation
Arguments
none
See also
procedure_setindexbase
procedure_fortrannotation
function_indexbase
*/

void dpuserProcedure_cnotation() {

    indexBase = 0;
}

#if 0
//Alex
//TODO: Check why this is commented out (by #if 0 above)?
/*!
userDialog
Create a dialog box for QFitsView
Syntax
userDialog function, labels [, types [, values] ]
Arguments
title: A string with the dpuser function to be executed. This will be shown also as the caption of the dialog box.
labels: A string array with the description of the parameters to be entered
types: Optional types of the arguments (as a string array): Can be either <b>int, real, fits</b>, or anything, in which case it will be treated as a string.
values: Optionally, default values for the entries can be given (as a string array).
Examples
Create a dialog box for the velmap function:
<code>userDialog "myvelmap", ["cube", "wavelength center", "fwhm"], ["fits", "real", "real"], ["", "2.13", ".001"]
*/

void dpuserProcedure_userDialog(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("userDialog", arg0, arg1);

#ifdef DPQT
    dpStringList dummy;
    userfunctionstruct data;
    int i;

    dummy = *arg1.arrvalue;
    for (i = 0; i < dummy.size(); i++)
        dummy[i] = dpString("");
    data.labels = *arg1.arrvalue;
    data.types = dummy;
    data.defaultValues = dummy;

    userDialogs.erase(*arg0.svalue);
    userDialogs[*arg0.svalue] = data;
#endif /* DPQT */
}

//Alex
void dpuserProcedure_userDialog(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
    checkProcArgs("userDialog", arg0, arg1, arg2);

#ifdef DPQT
    dpStringList dummy;
    userfunctionstruct data;
    int i;

    dummy = *arg1.arrvalue;
    for (i = 0; i < dummy.size(); i++)
        dummy[i] = dpString("");
    data.labels = *arg1.arrvalue;
    data.types = dummy;
    data.defaultValues = dummy;

    data.types = *arg2.arrvalue;

    userDialogs.erase(*arg0.svalue);
    userDialogs[*arg0.svalue] = data;
#endif /* DPQT */
}

//Alex
void dpuserProcedure_userDialog(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("userDialog", arg0, arg1, arg2, arg3);

#ifdef DPQT
    dpStringList dummy;
    userfunctionstruct data;
    int i;

    dummy = *arg1.arrvalue;
    for (i = 0; i < dummy.size(); i++)
        dummy[i] = dpString("");
    data.labels = *arg1.arrvalue;
    data.types = dummy;
    data.defaultValues = dummy;

    data.types = *arg2.arrvalue;
    data.defaultValues = *arg3.arrvalue;

    userDialogs.erase(*arg0.svalue);
    userDialogs[*arg0.svalue] = data;
#endif /* DPQT */
}

#endif /* 0 */

//Alex
void resetCompiledFuncsProcs() {
    std::vector<compiled_function>::iterator tempIterFunc = compiledfunctions.begin();
    std::vector<compiled_procedure>::iterator tempIterProc = compiledprocedures.begin();

    // unloading all compiled functions
    while (tempIterFunc != compiledfunctions.end()) {
    #ifdef WIN
        FreeLibrary((HINSTANCE)(*tempIterFunc).libHandle);
    #else
        dlclose((*tempIterFunc).libHandle);
    #endif
        (*tempIterFunc).libHandle = NULL;
        tempIterFunc++;
    }
    compiledfunctions.clear();

    // unloading all compiled procedures
    while (tempIterProc != compiledprocedures.end()) {
    #ifdef WIN
        FreeLibrary((HINSTANCE)(*tempIterProc).libHandle);
    #else
        dlclose((*tempIterProc).libHandle);
    #endif
        (*tempIterProc).libHandle = NULL;
        tempIterProc++;
    }
    compiledprocedures.clear();
}

//Alex
/*!
compile
Converts a dpuser-script into C-code, compiles it and links it at runtime into the running dpuser-session. Unlike with user defined functions or procedures, it is not allowed to compile a function with the same name as aalready compiled procedure and vice versa.
Syntax
compile "filename"
Arguments
filename: The filename of the dpuser-script to convert
Switches
/c: Adds needed headers and forward declarations to existing C-code and links it on runtime. The general data type to use must be 'dpuserType'. Functions and procedures must begin like shown in the examples below.
/reset: Unloads all compiled functions and procedures. See example below.
Examples
To compile c-code, functions must be defined as follows:
<code>extern "C" dpuserType funcName(dpuserType &a, ...) { ... }
<code>   ...;
<code>   return funcName;
<code>}
<br>Procedures must be defined as follows:
<code>extern "C" void procName(dpuserType &a, ...) {
<code>   ...;
<code>   return;
<code>}
<br>To unload all functions and procedures:
<code>compile "", /reset
*/

void dpuserProcedure_compile(dpuserType arg0, dpString option1) {
    checkProcArgs("compile", arg0);

    if (option1 == "reset") {
        resetCompiledFuncsProcs();
        return;
    }

#ifdef WIN
    SetLastError(0);
#endif
    // *** Check if script-file exists ***
    dpString scriptFilename = dpString(arg0.svalue->c_str());
    FILE *fileExists = fopen(scriptFilename.c_str(), "rb");
    if (fileExists == 0) {
        dp_output(">>> File %s doesn't exist!\n", scriptFilename.c_str());
        return;
    }
    fclose(fileExists);

    // *** Declarations ***
    typedef dpuserType (*funcDecl0)(void);
    typedef dpuserType (*funcDecl1)(dpuserType &);
    typedef dpuserType (*funcDecl2)(dpuserType &,dpuserType &);
    typedef dpuserType (*funcDecl3)(dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl4)(dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl5)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl6)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl7)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl8)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl9)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl10)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl11)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl12)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl13)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl14)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl15)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl16)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl17)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl18)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl19)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);
    typedef dpuserType (*funcDecl20)(dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &, dpuserType &);

    typedef void (*procDecl0)(void);
    typedef void (*procDecl1)(dpuserType&);
    typedef void (*procDecl2)(dpuserType&, dpuserType&);
    typedef void (*procDecl3)(dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl4)(dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl5)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl6)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl7)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl8)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl9)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl10)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl11)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl12)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl13)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl14)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl15)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl16)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl17)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl18)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl19)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);
    typedef void (*procDecl20)(dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&, dpuserType&);

    // *** Parse dpuser-script and convert to c-code ***
    // *** Function-info of generated c-function is pushed into compiledfunctions-vector ***
     try {
        if (option1 == "idl") {
            main_idl2c((char *)scriptFilename.c_str());
        } else if (option1 == "c") {
            compileCcode((char *)scriptFilename.c_str());
        } else {
            main_dpuser2c((char *)scriptFilename.c_str());
      }
     }
     catch (dpuserTypeException e) {
        dp_output(">>> Parsing dpuser-script failed.\n");
         return;
     }

    // fetch info (nargs & name) of function or procedure to be compiled
    while (!funcProcOrder.empty()) {
//printf("############################################\n");
        FuncProcInfo info = funcProcOrder.front();
        funcProcOrder.pop_front();

      // *** Check if this function or procedure has the same name as a builtin or a stored
      // *** function or procedure
      if (info.id == funcID) {
         switch (funcWord_for_compile(info.name)) {
            case -1:
               dp_output(">>> \"%s\" exists already as builtin function!\n", info.name.c_str());
               return;
            case -2:
               dp_output(">>> \"%s\" exists already as stored function!\n", info.name.c_str());
               return;
            case -3:
               dp_output(">>> \"%s\" exists already as compiled procedure!\n", info.name.c_str());
               return;
            default:
               // doesn't exist as builtin or stored function
               break; 
         }
        } else {
         switch (pgWord_for_compile(info.name)) {
            case -1:
               dp_output(">>> \"%s\" exists already as builtin procedure!\n", info.name.c_str());
               return;
            case -2:
               dp_output(">>> \"%s\" exists already as stored procedure!\n", info.name.c_str());
               return;
            case -3:
               dp_output(">>> \"%s\" exists already as compiled function!\n", info.name.c_str());
               return;
            default:
               // doesn't exist as builtin or stored procedure
               break; 
         }
        }

        // *** Check if this function or procedure has already been compiled. If yes, unload it
        // *** (and all functions and procedures compiled after it). ***
        // if function or procedure is already existing get iterator to it
        bool funcorprocExists = false;
        int nrFuncProc = -1;
        std::vector<compiled_function>::iterator iterFuncExisting;
        std::vector<compiled_procedure>::iterator iterProcExisting;
        if (info.id == funcID) {
            iterFuncExisting = compiledfunctions.begin();
            while (iterFuncExisting != compiledfunctions.end()) {
                if ((*iterFuncExisting).name == info.name) {
                    funcorprocExists = true;
                    nrFuncProc = (*iterFuncExisting).nrCompiled;
                    break;
                }
                iterFuncExisting++;
            }
        } else {
            iterProcExisting = compiledprocedures.begin();
            while (iterProcExisting != compiledprocedures.end()) {
                if ((*iterProcExisting).name == info.name) {
                    funcorprocExists = true;
                    nrFuncProc = (*iterProcExisting).nrCompiled;
                    break;
                }
                iterProcExisting++;
            }
        }

    #ifdef WIN
        // Get tempDir-path
        char FullName[MAX_PATH + 1];
        GetTempPath(MAX_PATH, FullName);
        dpString tempPath = dpString(FullName);
        // Get AppDir-path
        GetModuleFileName(NULL, FullName, MAX_PATH);
        dpString AppPath = dpString(FullName);
        dpint64 begin = AppPath.rfind('\\');
        AppPath.remove(begin + 1, AppPath.length() - begin);
    #endif

        // Functions and procedures are compiled in a certain order (functions and procedures mixed!)
        // So if for example a function in the middle of compiledfunctions is recompiled all subsequent
        // functions have to be unloaded and also all the procedures which have been compiled after that
        // the compile order can be seen in the nrCompiled-member of the compiled_function- and
        // compiled_procedure-classes
        std::vector<compiled_function>::iterator tempIterFunc;
        std::vector<compiled_procedure>::iterator tempIterProc;

//printf("nFuncProc = %d\n", nrFuncProc);
        if (funcorprocExists) {
            // unload all functions compiled after the one iterFuncExisting is pointing to
            tempIterFunc = compiledfunctions.begin();
            while (tempIterFunc != compiledfunctions.end()) {
                if ((*tempIterFunc).nrCompiled >= nrFuncProc) {
//printf(">>> unloading function: %s\n", (*tempIterFunc).name.c_str());
                #ifdef WIN
                    FreeLibrary((HINSTANCE)(*tempIterFunc).libHandle);
                #else
                    dlclose((*tempIterFunc).libHandle);
                #endif
                    (*tempIterFunc).libHandle = NULL;
                }
                tempIterFunc++;
            }

            // unload all procedures compiled after the one iterFuncExisting is pointing to
            tempIterProc = compiledprocedures.begin();
            while (tempIterProc != compiledprocedures.end()) {
                if ((*tempIterProc).nrCompiled >= nrFuncProc) {
//printf(">>> unloading procedure: %s\n", (*tempIterProc).name.c_str());
                #ifdef WIN
                    FreeLibrary((HINSTANCE)(*tempIterProc).libHandle);
                #else
                    dlclose((*tempIterProc).libHandle);
                #endif
                    (*tempIterProc).libHandle = NULL;
                }
                tempIterProc++;
            }

            #ifdef WIN
            // Delete dll of function to recompile, otherwise it won't be recompiled
            dpString t = "del " + tempPath + info.name + ".dll";
            if (system(t.c_str()) != 0) {
                t = ">>> Failed deleting file: " + info.name + ".dll";
                throw dpuserTypeException((char*)t.c_str());
                return;
            }
            #endif
        }

        // *** Compile & link created C-code, create shared library ***
        dpString dpqt, cmd = "g++ ";

        #ifdef DBG
            cmd += "-g ";
        #endif

        #ifdef DPQT
            dpqt = "-DDPQT ";
        #endif

      int maxFuncProc = 0, ii = 0;
        #if defined LINUX
            cmd += "-shared -fPIC "+ dpqt + info.name + ".cpp -o " + info.name + ".dll ";
        #elif defined MACOSX
            cmd += "-dynamic -bundle -undefined dynamic_lookup "+ dpqt + info.name + ".cpp -o " + info.name + ".dll ";
        #elif defined WIN

            // add actual function to compile-command
            cmd += "-shared " + dpqt + info.name + ".cpp -o " + tempPath + info.name + ".dll ";

            // add dpuser.dll to compile-command
            #ifdef DBG
            #ifdef DPQT
            cmd += AppPath + "QFitsViewD.dll ";
            #else
            cmd += AppPath + "dpuserD.dll ";
            #endif /* DPQT */
            #else
            #ifdef DPQT
            cmd += AppPath + "QFitsView.dll ";
            #else
            cmd += AppPath + "dpuser.dll ";
            #endif /* DPQT */
            #endif

            // add dlls of other already compiled functions to compile-command
            // in the right dependency-order!
            if (nrFuncProc == -1)
                maxFuncProc = compiledfunctions.size() + compiledprocedures.size();
            else
                maxFuncProc = nrFuncProc;

            while (ii < maxFuncProc) {
                tempIterFunc = compiledfunctions.begin();
                while (tempIterFunc != compiledfunctions.end()) {
                    if ((*tempIterFunc).nrCompiled == ii) {
                        cmd += tempPath + (*tempIterFunc).name + ".dll ";
                        break;
                    }
                    tempIterFunc++;
                }
                tempIterProc = compiledprocedures.begin();
                while (tempIterProc != compiledprocedures.end()) {
                    if ((*tempIterProc).nrCompiled == ii) {
                        cmd += tempPath + (*tempIterProc).name + ".dll ";
                        break;
                    }
                    tempIterProc++;
                }
                ii++;
            }
        #endif

        // compile & link
        dp_output("%s\n", cmd.c_str());


        if (system(cmd.c_str()) != 0) {
            throw dpuserTypeException(">>> Failed compiling and linking the generated C-code.\n");
            return;
        }

        // *** load shared library for new function ***
        void *libHandle;
    #ifdef WIN
        // Windows
        libHandle = LoadLibrary((tempPath + info.name + ".dll").c_str());
        if (libHandle == NULL) {
            LPVOID lpMsgBuf;
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
            dpString msg(">>> Failed loading generated library: " + tempPath + info.name + ".dll\n");
            msg += (char*)lpMsgBuf;
            LocalFree( lpMsgBuf );
            msg += "\n";
            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
            return;
        }
    #else
        // Linux
        libHandle = dlopen((dpDir::currentDirPath() + "/" + info.name + ".dll").c_str(), RTLD_LAZY|RTLD_GLOBAL);
        if (libHandle == NULL) {
            dpString msg(">>> Failed loading generated library: " + dpDir::currentDirPath() + "/" + info.name + ".dll\n");
            msg += dlerror();
            msg += "\n";
            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
            return;
        }
    #endif

        // add library-handle, filename and pointer to function/procedure to newCompiledFunction or newCompiledProcedure
        compiled_function newCompiledFunction;
        compiled_procedure newCompiledProcedure;
        if (info.id == funcID) {
            newCompiledFunction.libHandle = libHandle;
            newCompiledFunction.name = info.name;
            newCompiledFunction.nargs = info.nargs;
         newCompiledFunction.displaySyntax = info.displaySyntax;
        } else {
            newCompiledProcedure.libHandle = libHandle;
            newCompiledProcedure.nargs = info.nargs;
            newCompiledProcedure.name = info.name;
         newCompiledProcedure.displaySyntax = info.displaySyntax;
        }

    #ifdef WIN
        // Windows
        if (info.id == funcID) {
            switch (info.nargs) {
                case 0: newCompiledFunction.arg0 = (funcDecl0)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 1: newCompiledFunction.arg1 = (funcDecl1)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 2: newCompiledFunction.arg2 = (funcDecl2)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 3: newCompiledFunction.arg3 = (funcDecl3)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 4: newCompiledFunction.arg4 = (funcDecl4)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 5: newCompiledFunction.arg5 = (funcDecl5)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 6: newCompiledFunction.arg6 = (funcDecl6)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 7: newCompiledFunction.arg7 = (funcDecl7)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 8: newCompiledFunction.arg8 = (funcDecl8)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 9: newCompiledFunction.arg9 = (funcDecl9)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 10: newCompiledFunction.arg10 = (funcDecl10)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 11: newCompiledFunction.arg11 = (funcDecl11)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 12: newCompiledFunction.arg12 = (funcDecl12)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 13: newCompiledFunction.arg13 = (funcDecl13)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 14: newCompiledFunction.arg14 = (funcDecl14)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 15: newCompiledFunction.arg15 = (funcDecl15)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 16: newCompiledFunction.arg16 = (funcDecl16)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 17: newCompiledFunction.arg17 = (funcDecl17)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 18: newCompiledFunction.arg18 = (funcDecl18)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 19: newCompiledFunction.arg19 = (funcDecl19)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 20: newCompiledFunction.arg20 = (funcDecl20)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
            }
        } else{
            switch (info.nargs) {
                case 0: newCompiledProcedure.arg0 = (procDecl0)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 1: newCompiledProcedure.arg1 = (procDecl1)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 2: newCompiledProcedure.arg2 = (procDecl2)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 3: newCompiledProcedure.arg3 = (procDecl3)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 4: newCompiledProcedure.arg4 = (procDecl4)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 5: newCompiledProcedure.arg5 = (procDecl5)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 6: newCompiledProcedure.arg6 = (procDecl6)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 7: newCompiledProcedure.arg7 = (procDecl7)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 8: newCompiledProcedure.arg8 = (procDecl8)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 9: newCompiledProcedure.arg9 = (procDecl9)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 10: newCompiledProcedure.arg10 = (procDecl10)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 11: newCompiledProcedure.arg11 = (procDecl11)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 12: newCompiledProcedure.arg12 = (procDecl12)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 13: newCompiledProcedure.arg13 = (procDecl13)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 14: newCompiledProcedure.arg14 = (procDecl14)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 15: newCompiledProcedure.arg15 = (procDecl15)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 16: newCompiledProcedure.arg16 = (procDecl16)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 17: newCompiledProcedure.arg17 = (procDecl17)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 18: newCompiledProcedure.arg18 = (procDecl18)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 19: newCompiledProcedure.arg19 = (procDecl19)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
                case 20: newCompiledProcedure.arg20 = (procDecl20)GetProcAddress((HINSTANCE)libHandle, info.name.c_str()); break;
            }
        }
        if (GetLastError() != 0) {
            LPVOID lpMsgBuf;
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
            dpString msg(">>> Error:\n");
            msg += (char*)lpMsgBuf;
            LocalFree( lpMsgBuf );
            msg += "\n";
            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
            return;
        }
    #else
        // Linux
        if (info.id == funcID) {
            switch (info.nargs) {
                case 0: newCompiledFunction.arg0 = (funcDecl0)dlsym(libHandle, info.name.c_str()); break;
                case 1: newCompiledFunction.arg1 = (funcDecl1)dlsym(libHandle, info.name.c_str()); break;
                case 2: newCompiledFunction.arg2 = (funcDecl2)dlsym(libHandle, info.name.c_str()); break;
                case 3: newCompiledFunction.arg3 = (funcDecl3)dlsym(libHandle, info.name.c_str()); break;
                case 4: newCompiledFunction.arg4 = (funcDecl4)dlsym(libHandle, info.name.c_str()); break;
                case 5: newCompiledFunction.arg5 = (funcDecl5)dlsym(libHandle, info.name.c_str()); break;
                case 6: newCompiledFunction.arg6 = (funcDecl6)dlsym(libHandle, info.name.c_str()); break;
                case 7: newCompiledFunction.arg7 = (funcDecl7)dlsym(libHandle, info.name.c_str()); break;
                case 8: newCompiledFunction.arg8 = (funcDecl8)dlsym(libHandle, info.name.c_str()); break;
                case 9: newCompiledFunction.arg9 = (funcDecl9)dlsym(libHandle, info.name.c_str()); break;
                case 10: newCompiledFunction.arg10 = (funcDecl10)dlsym(libHandle, info.name.c_str()); break;
                case 11: newCompiledFunction.arg11 = (funcDecl11)dlsym(libHandle, info.name.c_str()); break;
                case 12: newCompiledFunction.arg12 = (funcDecl12)dlsym(libHandle, info.name.c_str()); break;
                case 13: newCompiledFunction.arg13 = (funcDecl13)dlsym(libHandle, info.name.c_str()); break;
                case 14: newCompiledFunction.arg14 = (funcDecl14)dlsym(libHandle, info.name.c_str()); break;
                case 15: newCompiledFunction.arg15 = (funcDecl15)dlsym(libHandle, info.name.c_str()); break;
                case 16: newCompiledFunction.arg16 = (funcDecl16)dlsym(libHandle, info.name.c_str()); break;
                case 17: newCompiledFunction.arg17 = (funcDecl17)dlsym(libHandle, info.name.c_str()); break;
                case 18: newCompiledFunction.arg18 = (funcDecl18)dlsym(libHandle, info.name.c_str()); break;
                case 19: newCompiledFunction.arg19 = (funcDecl19)dlsym(libHandle, info.name.c_str()); break;
                case 20: newCompiledFunction.arg20 = (funcDecl20)dlsym(libHandle, info.name.c_str()); break;
            }
        } else {
            switch (info.nargs) {
                case 0: newCompiledProcedure.arg0 = (procDecl0)dlsym(libHandle, info.name.c_str()); break;
                case 1: newCompiledProcedure.arg1 = (procDecl1)dlsym(libHandle, info.name.c_str()); break;
                case 2: newCompiledProcedure.arg2 = (procDecl2)dlsym(libHandle, info.name.c_str()); break;
                case 3: newCompiledProcedure.arg3 = (procDecl3)dlsym(libHandle, info.name.c_str()); break;
                case 4: newCompiledProcedure.arg4 = (procDecl4)dlsym(libHandle, info.name.c_str()); break;
                case 5: newCompiledProcedure.arg5 = (procDecl5)dlsym(libHandle, info.name.c_str()); break;
                case 6: newCompiledProcedure.arg6 = (procDecl6)dlsym(libHandle, info.name.c_str()); break;
                case 7: newCompiledProcedure.arg7 = (procDecl7)dlsym(libHandle, info.name.c_str()); break;
                case 8: newCompiledProcedure.arg8 = (procDecl8)dlsym(libHandle, info.name.c_str()); break;
                case 9: newCompiledProcedure.arg9 = (procDecl9)dlsym(libHandle, info.name.c_str()); break;
                case 10: newCompiledProcedure.arg10 = (procDecl10)dlsym(libHandle, info.name.c_str()); break;
                case 11: newCompiledProcedure.arg11 = (procDecl11)dlsym(libHandle, info.name.c_str()); break;
                case 12: newCompiledProcedure.arg12 = (procDecl12)dlsym(libHandle, info.name.c_str()); break;
                case 13: newCompiledProcedure.arg13 = (procDecl13)dlsym(libHandle, info.name.c_str()); break;
                case 14: newCompiledProcedure.arg14 = (procDecl14)dlsym(libHandle, info.name.c_str()); break;
                case 15: newCompiledProcedure.arg15 = (procDecl15)dlsym(libHandle, info.name.c_str()); break;
                case 16: newCompiledProcedure.arg16 = (procDecl16)dlsym(libHandle, info.name.c_str()); break;
                case 17: newCompiledProcedure.arg17 = (procDecl17)dlsym(libHandle, info.name.c_str()); break;
                case 18: newCompiledProcedure.arg18 = (procDecl18)dlsym(libHandle, info.name.c_str()); break;
                case 19: newCompiledProcedure.arg19 = (procDecl19)dlsym(libHandle, info.name.c_str()); break;
                case 20: newCompiledProcedure.arg20 = (procDecl20)dlsym(libHandle, info.name.c_str()); break;
            }
        }

        const char *error = dlerror();
        if (error != NULL) {
            dpString msg(">>> Error:\n");
            msg += error;
            msg += "\n";
            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
            return;
        }
    #endif

        // *** add new function to compiledfunctions-vector ***
        if (funcorprocExists) {
            // *** replace recompiled function or procedure ***
            if (info.id == funcID) {
                // if function exists already replace it in the compiledfunctions-vector
//printf("replace func: %s\n", (*iterFuncExisting).name.c_str());
                newCompiledFunction.nrCompiled = (*iterFuncExisting).nrCompiled;
                *iterFuncExisting = newCompiledFunction;
            } else {
                // if procedure exists already replace it in the compiledprocedures-vector
//printf("replace proc: %s\n", (*iterProcExisting).name.c_str());
                newCompiledProcedure.nrCompiled = (*iterProcExisting).nrCompiled;
                *iterProcExisting = newCompiledProcedure;
            }

            maxFuncProc = compiledfunctions.size() + compiledprocedures.size();
            ii = nrFuncProc + 1;
            while (ii < maxFuncProc) {
                tempIterFunc = compiledfunctions.begin();
                while (tempIterFunc != compiledfunctions.end()) {
                    if (((*tempIterFunc).libHandle == NULL) && ((*tempIterFunc).nrCompiled == ii)){
                    #ifdef WIN
//printf("reload func: %s\n", (*tempIterFunc).name.c_str());
                        libHandle = LoadLibrary((tempPath + (*tempIterFunc).name + ".dll").c_str());
                        if (libHandle == NULL) {
                            LPVOID lpMsgBuf;
                            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
                            dpString msg(">>> Failed loading generated library: " + tempPath + (*tempIterFunc).name + ".dll\n");
                            msg += (char*)lpMsgBuf;
                            LocalFree( lpMsgBuf );
                            msg += "\n";
                            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
                            return;
                        }
                    #else
                        libHandle = dlopen((dpDir::currentDirPath() + "/" + (*tempIterFunc).name + ".dll").c_str(), RTLD_LAZY|RTLD_GLOBAL);
                        if (libHandle == NULL) {
                            dpString msg(">>> Failed loading generated library: " + dpDir::currentDirPath() + "/" + (*tempIterFunc).name + ".dll\n");
                            msg += dlerror();
                            msg += "\n";
                            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
                            return;
                        }
                    #endif
                        (*tempIterFunc).libHandle = libHandle;
                    }
                    tempIterFunc++;
                }

                tempIterProc = compiledprocedures.begin();
                while (tempIterProc != compiledprocedures.end()) {
                    if (((*tempIterProc).libHandle == NULL) && ((*tempIterProc).nrCompiled == ii)) {
                    #ifdef WIN
//printf("reload proc: %s\n", (*tempIterProc).name.c_str());
                        libHandle = LoadLibrary((tempPath + (*tempIterProc).name + ".dll").c_str());
                        if (libHandle == NULL) {
                            LPVOID lpMsgBuf;
                            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
                            dpString msg(">>> Failed loading generated library: " + tempPath + (*tempIterProc).name + ".dll\n");
                            msg += (char*)lpMsgBuf;
                            LocalFree( lpMsgBuf );
                            msg += "\n";
                            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
                            return;
                        }
                    #else
                        libHandle = dlopen((dpDir::currentDirPath() + "/" + (*tempIterProc).name + ".dll").c_str(), RTLD_LAZY|RTLD_GLOBAL);
                        if (libHandle == NULL) {
                            dpString msg(">>> Failed loading generated library: " + dpDir::currentDirPath() + "/" + (*tempIterProc).name + ".dll\n");
                            msg += dlerror();
                            msg += "\n";
                            throw dpuserTypeException(const_cast<char*>(msg.c_str()));
                            return;
                        }
                    #endif
                        (*tempIterProc).libHandle = libHandle;
                    }
                    tempIterProc++;
                }
                ii++;
            }
        } else {
            int newNr = compiledfunctions.size() + compiledprocedures.size();
            if (info.id == funcID) {
                // if function doesn't exist add it to the compiledfunctions-vector
                newCompiledFunction.nrCompiled = newNr;
                compiledfunctions.push_back(newCompiledFunction);
//printf("add func: %s\n", newCompiledFunction.name.c_str());
            } else {
                // if procedure doesn't exist add it to the compiledprocedures-vector
                newCompiledProcedure.nrCompiled = newNr;
                compiledprocedures.push_back(newCompiledProcedure);
//printf("add proc: %s\n", newCompiledProcedure.name.c_str());
            }
        }
/*printf("--- Status -----------------------------------------------\n");
printf("functions:\n");
tempIterFunc = compiledfunctions.begin();
while (tempIterFunc != compiledfunctions.end()) {
    printf("%d, %s, %p\n", (*tempIterFunc).nrCompiled, (*tempIterFunc).name.c_str(), (*tempIterFunc).libHandle);
    tempIterFunc++;
}
printf("procedures:\n");
tempIterProc = compiledprocedures.begin();
while (tempIterProc != compiledprocedures.end()) {
    printf("%d, %s, %p\n", (*tempIterProc).nrCompiled, (*tempIterProc).name.c_str(), (*tempIterProc).libHandle);
    tempIterProc++;
}
printf("----------------------------------------------------------\n");
*/        if (info.id == funcID) {
            dp_output("Compiled function %s\n", info.name.c_str());
        } else {
            dp_output("Compiled procedure %s\n", info.name.c_str());
        }
    }
}

//Alex
void dpuserProcedure_pgqtxt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqtxt", arg0, arg1, arg2, arg3, arg4, arg5, arg6);

    variables[arg5.toInt()].type = typeFits;
    variables[arg5.toInt()].fvalue = CreateFits();
    if (!variables[arg5.toInt()].fvalue->create(4, 1)) return;
    variables[arg6.toInt()].type = typeFits;
    variables[arg6.toInt()].fvalue = CreateFits();
    if (!variables[arg6.toInt()].fvalue->create(4, 1)) return;
    cpgqtxt(arg0.toDouble(), arg1.toDouble(), arg2.toDouble(), arg3.toDouble(), arg4.svalue->c_str(), variables[arg5.toInt()].fvalue->r4data, variables[arg6.toInt()].fvalue->r4data);
#endif
}

//Alex
void dpuserProcedure_pgband(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5, dpuserType arg6) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgband", arg0, arg1, arg2, arg3, arg4, arg5, arg6);

    float x, y;
    char ch[2];

    ch[1] = (char)0;
    if (variables[arg4.toInt()].type == typeCon)
        x = (float)variables[arg4.toInt()].lvalue;
    else
        x = (float)variables[arg4.toInt()].dvalue;
    if (variables[arg5.toInt()].type == typeCon)
        y = (float)variables[arg5.toInt()].lvalue;
    else y = (float)variables[arg5.toInt()].dvalue;
    cpgband(arg0.toInt(), arg1.toInt(), arg2.toDouble(), arg3.toDouble(), &x, &y, ch);

    variables[arg4.toInt()].type = typeDbl;
    variables[arg4.toInt()].dvalue = (double)x;

    variables[arg5.toInt()].type = typeDbl;
    variables[arg5.toInt()].dvalue = (double)y;

    variables[arg6.toInt()].type = typeStr;
    variables[arg6.toInt()].svalue = CreateString(ch);
#endif
}

//Alex
void dpuserProcedure_pgcurse(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgcurse", arg0, arg1, arg2);

    float x, y;
    char ch[2];

    ch[1] = (char)0;
    if (variables[arg0.toInt()].type == typeCon)
        x = (float)variables[arg0.toInt()].lvalue;
    else
        x = (float)variables[arg0.toInt()].dvalue;
    if (variables[arg1.toInt()].type == typeCon)
        y = (float)variables[arg1.toInt()].lvalue;
    else
        y = (float)variables[arg1.toInt()].dvalue;
    cpgcurs(&x, &y, ch);

    variables[arg0.toInt()].type=typeDbl;
    variables[arg0.toInt()].dvalue=(double)(x);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(y);

    variables[arg2.toInt()].type = typeStr;
    variables[arg2.toInt()].svalue = CreateString(ch);
#endif
}

//Alex
void dpuserProcedure_pgcurs(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgcurs", arg0, arg1, arg2);

    float x, y;
    char ch[2];

    ch[1] = (char)0;
    if (variables[arg0.toInt()].type == typeCon)
        x = (float)variables[arg0.toInt()].lvalue;
    else
        x = (float)variables[arg0.toInt()].dvalue;
    if (variables[arg1.toInt()].type == typeCon)
        y = (float)variables[arg1.toInt()].lvalue;
    else
        y = (float)variables[arg1.toInt()].dvalue;
    cpgcurs(&x, &y, ch);
    variables[arg0.toInt()].type = typeDbl;
    variables[arg0.toInt()].dvalue = (double)x;
    variables[arg1.toInt()].type = typeDbl;
    variables[arg1.toInt()].dvalue = (double)y;
    variables[arg2.toInt()].type = typeStr;
    variables[arg2.toInt()].svalue = CreateString(ch);
#endif
}

//Alex
/*!
spec3d
Draw an averaged spectrum of the cube multiplied by the mask.
Syntax
spec3d cube, mask [,title=string] [,xtitle=string] [,ytitle=string]
Arguments
cube: A 3-dimensional matrix
mask: A 2-dimensional matrix
*/

void dpuserProcedure_spec3d(dpuserType arg0, dpuserType arg1) {
    checkProcArgs("pgcurs", arg0, arg1);

#ifdef HAS_PGPLOT
    Fits data, _tmp;
    int i;

    data.create(arg0.fvalue->Naxis(3), 1);
    for (i = 1; i <= arg0.fvalue->Naxis(3); i++) {
        arg0.fvalue->extractRange(_tmp, -1, -1, -1, -1, i, i);
        _tmp *= *arg1.fvalue;
        data.r4data[i] = (float)_tmp.get_avg();
    }
    plot(NULL, &data, 0.0, 0.0, 0, 0);
#endif /* HAS_PGPLOT */
}

//Alex
void dpuserProcedure_pgqah(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pgqah", arg0, arg1, arg2);

    cpgqah(&pgi[0], &pgf[1], &pgf[2]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);
#endif
}

//Alex
void dpuserProcedure_pgqcf(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqcf", arg0);

    cpgqcf(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqch(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqch", arg0);

    cpgqch(&pgf[0]);

    variables[arg0.toInt()].type=typeDbl;
    variables[arg0.toInt()].lvalue=(double)(pgf[0]);
#endif
}

//Alex
void dpuserProcedure_pgqci(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqci", arg0);

    cpgqci(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqcir(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqcir", arg0, arg1);

    cpgqcir(&pgi[0], &pgi[1]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);

    variables[arg1.toInt()].type=typeCon;
    variables[arg1.toInt()].lvalue=(long)(pgi[1]);
#endif
}

//Alex
void dpuserProcedure_pgqclp(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqclp", arg0);

    cpgqclp(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqcol(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqcol", arg0, arg1);

    cpgqcol(&pgi[0], &pgi[1]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);

    variables[arg1.toInt()].type=typeCon;
    variables[arg1.toInt()].lvalue=(long)(pgi[1]);
#endif
}

//Alex
void dpuserProcedure_pgqcr(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqcr", arg0, arg1, arg2, arg3);

    cpgqcr(arg0.toInt(), &pgf[1], &pgf[2], &pgf[3]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);

    variables[arg3.toInt()].type=typeDbl;
    variables[arg3.toInt()].dvalue=(double)(pgf[3]);
#endif
}

//Alex
void dpuserProcedure_pgqcs(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqcs", arg0, arg1, arg2);

    cpgqcs(arg0.toInt(), &pgf[1], &pgf[2]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);
#endif
}

//Alex
void dpuserProcedure_pgqdt(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4, dpuserType arg5) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pgqdt", arg0, arg1, arg2, arg3, arg4, arg5);

    for (int i = 0; i < 256; i++)
        cans1[i] = cans2[i] = (char)0;
    pgi[2] = pgi[4] = 256;

    cpgqdt(arg0.toInt(), cans1, &pgi[2], cans2, &pgi[4], &pgi[5]);

    variables[arg1.toInt()].type = typeStr;
    variables[arg1.toInt()].svalue = CreateString(cans1);

    variables[arg2.toInt()].type=typeCon;
    variables[arg2.toInt()].lvalue=(long)(pgi[2]);

    variables[arg3.toInt()].type = typeStr;
    variables[arg3.toInt()].svalue = CreateString(cans2);

    variables[arg4.toInt()].type=typeCon;
    variables[arg4.toInt()].lvalue=(long)(pgi[4]);

    variables[arg5.toInt()].type=typeCon;
    variables[arg5.toInt()].lvalue=(long)(pgi[5]);
#endif
}

//Alex
void dpuserProcedure_pgqfs(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqfs", arg0);

    cpgqfs(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqhs(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqhs", arg0, arg1, arg2);

    cpgqhs(&pgf[0], &pgf[1], &pgf[2]);

    variables[arg0.toInt()].type=typeDbl;
    variables[arg0.toInt()].dvalue=(double)(pgf[0]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);
#endif
}

//Alex
void dpuserProcedure_pgqid(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqid", arg0);

    cpgqid(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqinf(dpuserType arg0, dpuserType arg1, dpuserType arg2) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqinf", arg0, arg1, arg2);

    for (int i = 0; i < 256; i++)
        cans1[i] = (char)0;
    pgi[2] = 256;
    cpgqinf(arg0.svalue->c_str(), cans1, &pgi[2]);
    variables[arg1.toInt()].type = typeStr;
    variables[arg1.toInt()].svalue = CreateString(cans1);

    variables[arg2.toInt()].type=typeCon;
    variables[arg2.toInt()].lvalue=(long)(pgi[2]);
#endif
}

//Alex
void dpuserProcedure_pgqitf(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqitf", arg0);

    cpgqitf(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqls(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
   checkProcArgs("pgqls", arg0);

    cpgqls(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqlw(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqlw", arg0);

    cpgqlw(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqndt(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqndt", arg0);

    cpgqndt(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqpos(dpuserType arg0, dpuserType arg1) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqpos", arg0, arg1);

    cpgqpos(&pgf[0], &pgf[1]);

    variables[arg0.toInt()].type=typeDbl;
    variables[arg0.toInt()].dvalue=(double)(pgf[0]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);
#endif
}

//Alex
void dpuserProcedure_pgqtbg(dpuserType arg0) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqtbg", arg0);

    cpgqtbg(&pgi[0]);

    variables[arg0.toInt()].type=typeCon;
    variables[arg0.toInt()].lvalue=(long)(pgi[0]);
#endif
}

//Alex
void dpuserProcedure_pgqvp(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqvp", arg0, arg1, arg2, arg3, arg4);

    cpgqvp(arg0.toInt(), &pgf[1], &pgf[2], &pgf[3], &pgf[4]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);

    variables[arg3.toInt()].type=typeDbl;
    variables[arg3.toInt()].dvalue=(double)(pgf[3]);

    variables[arg4.toInt()].type=typeDbl;
    variables[arg4.toInt()].dvalue=(double)(pgf[4]);
#endif
}

//Alex
void dpuserProcedure_pgqvsz(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpuserType arg4) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqvsz", arg0, arg1, arg2, arg3, arg4);

    cpgqvsz(arg0.toInt(), &pgf[1], &pgf[2], &pgf[3], &pgf[4]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);

    variables[arg3.toInt()].type=typeDbl;
    variables[arg3.toInt()].dvalue=(double)(pgf[3]);

    variables[arg4.toInt()].type=typeDbl;
    variables[arg4.toInt()].dvalue=(double)(pgf[4]);
#endif
}

//Alex
void dpuserProcedure_pgqwin(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgqwin", arg0, arg1, arg2, arg3);

    cpgqwin(&pgf[0], &pgf[1], &pgf[2], &pgf[3]);

    variables[arg0.toInt()].type=typeDbl;
    variables[arg0.toInt()].dvalue=(double)(pgf[0]);

    variables[arg1.toInt()].type=typeDbl;
    variables[arg1.toInt()].dvalue=(double)(pgf[1]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);

    variables[arg3.toInt()].type=typeDbl;
    variables[arg3.toInt()].dvalue=(double)(pgf[3]);
#endif
}

//Alex
void dpuserProcedure_pgrnge(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
#ifndef HAS_PGPLOT
    throw dpuserTypeException("dpuser was compiled without PGPLOT support");
#else
    checkProcArgs("pgrnge", arg0, arg1, arg2, arg3);

    cpgrnge(arg0.toDouble(), arg1.toDouble(), &pgf[2], &pgf[3]);

    variables[arg2.toInt()].type=typeDbl;
    variables[arg2.toInt()].dvalue=(double)(pgf[2]);

    variables[arg3.toInt()].type=typeDbl;
    variables[arg3.toInt()].dvalue=(double)(pgf[3]);
#endif
}

//Alex
/*!
plot
Plots the 1-dimensional vector y. If x is given, x versus y is plot, else the running number versus y is plot. ymin and ymax can be specified to set the plot range in the y axes. If symbol is given and >= -31, each point will be represented by a symbol, else the lines will be connected by a polyline. See "help pgpt" for a description of available symbols.
Syntax
plot [x, ] y [,title=string] [,xtitle=string] [,ytitle=string] [,symbol=integer] [, ymin] [, ymax] [, /xlog] [, /ylog] [, /noclose]
See also
pgplot_pgpt
*/

void dpuserProcedure_plot(dpuserType arg0, dpString option1, dpString option2, dpString option3) {
    checkProcArgs("plot", arg0);

#ifdef HAS_PGPLOT
    int method = 0;
    int closeorcontinue = 0;

    if (variables[6].lvalue != 0) {
        method = variables[6].lvalue;
    } else {
        if (option1 == "xlog") method += 10;
        if (option2 == "ylog") method += 20;
    }
    if (option1 == "xlog") closeorcontinue += 1;
    if (option2 == "ylog") closeorcontinue += 2;
    if (option2 == "noclose") closeorcontinue += 4;

    plot(NULL, arg0.fvalue, 0.0, 0.0, method, closeorcontinue);
#endif /* HAS_PGPLOT */
}

//Alex
void dpuserProcedure_plot(dpuserType arg0, dpuserType arg1, dpString option1, dpString option2, dpString option3) {
    checkProcArgs("plot", arg0, arg1);

#ifdef HAS_PGPLOT
    int method = 0;
    int closeorcontinue = 0;

    if (variables[6].lvalue != 0) {
        method = variables[6].lvalue;
    } else {
        if (option1 == "xlog") method += 10;
        if (option2 == "ylog") method += 20;
    }
    if (option1 == "xlog") closeorcontinue += 1;
    if (option2 == "ylog") closeorcontinue += 2;
    if (option2 == "noclose") closeorcontinue += 4;

    if (arg1.type == typeFits) {
        plot(arg0.fvalue, arg1.fvalue, 0.0, 0.0, method, closeorcontinue);
    } else {
        plot(NULL, arg1.fvalue, 0.0, 0.0, method, closeorcontinue);
    }
#endif /* HAS_PGPLOT */
}

//Alex
void dpuserProcedure_plot(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpString option1, dpString option2, dpString option3) {
    checkProcArgs("plot", arg0, arg1, arg2);

#ifdef HAS_PGPLOT
    int method = 0;
    int closeorcontinue = 0;

    if (variables[6].lvalue != 0) {
        method = variables[6].lvalue;
    } else {
        if (option1 == "xlog") method += 10;
        if (option2 == "ylog") method += 20;
    }
    if (option1 == "xlog") closeorcontinue += 1;
    if (option2 == "ylog") closeorcontinue += 2;
    if (option2 == "noclose") closeorcontinue += 4;

    if (arg1.type == typeFits) {
        plot(arg0.fvalue, arg1.fvalue, 0.0, 0.0, method, closeorcontinue);
    } else {
        plot(NULL, arg0.fvalue, arg1.toDouble(), arg2.toDouble(), method, closeorcontinue);
    }
#endif /* HAS_PGPLOT */
}

//Alex
void dpuserProcedure_plot(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3, dpString option1, dpString option2, dpString option3) {
    checkProcArgs("plot", arg0, arg1, arg2, arg3);

#ifdef HAS_PGPLOT
    int method = 0;
    int closeorcontinue = 0;

    if (variables[6].lvalue != 0) {
        method = variables[6].lvalue;
    } else {
        if (option1 == "xlog") method += 10;
        if (option2 == "ylog") method += 20;
    }
    if (option1 == "xlog") closeorcontinue += 1;
    if (option2 == "ylog") closeorcontinue += 2;
    if (option2 == "noclose") closeorcontinue += 4;

        if (arg1.type == typeFits) {
            plot(arg0.fvalue, arg1.fvalue, arg2.toDouble(), arg3.toDouble(), method, closeorcontinue);
        } else {
            plot(NULL, arg1.fvalue, 0.0, 0.0, method, closeorcontinue);
        }
#endif /* HAS_PGPLOT */
}

#if 0
//Alex
//TODO why is this commented out (by #if 0 above)?
/*!
free
Release all memory taken by local variables.
Syntax
free
*/

void dpuserProcedure_free() {
    int i;
#ifdef DPQT
    int buffer1 = -1;
    for (i = 0; i < nvariables; i++)
        if (svariables[i] == "buffer1") buffer1 = i;
#endif /* DPQT */

    for (i = nglobals; i < nvariables; i++) {
        if (svariables[i] != "buffer1") {
#ifdef DPQT
// Lock QFitsView buffer
                        if (fitsMainWindow) buffers[i].data = NULL;
#endif /* DPQT */
            svariables[i] = "";
            variables[i].cvalue = NULL;
            variables[i].svalue = NULL;
            variables[i].fvalue = NULL;
            variables[i].ffvalue = NULL;
            variables[i].arrvalue = NULL;
            variables[i].dparrvalue = NULL;
            variables[i].type = typeUnknown;
        }
    }
#ifdef DPQT
    dpUpdateVar(buffer1);
#endif /* DPQT */
}

//Alex
void dpuserProcedure_free(dpuserType arg0) {
    checkProcArgs("free", arg0);

#ifdef DPQT
    int buffer1 = -1;

    for (int i = 0; i < nvariables; i++)
        if (svariables[i] == "buffer1") buffer1 = i;
#endif /* DPQT */

    int which = arg0.toInt();

    if ((which > nglobals) && (svariables[which] != "buffer1")) {
#ifdef DPQT
// Lock QFitsView buffer
                if (fitsMainWindow) {
            buffers[which].data = NULL;
            if (currentBuffer == which) dpUpdateVar(buffer1);
        }
#endif /* DPQT */
        svariables[which] = "";
        variables[which].cvalue = NULL;
        variables[which].svalue = NULL;
        variables[which].fvalue = NULL;
        variables[which].ffvalue = NULL;
        variables[which].arrvalue = NULL;
        variables[which].dparrvalue = NULL;
        variables[which].type = typeUnknown;
    }
}

#endif /* 0 */

#endif /* 0 */

//Alex
/*!
sao
Uses ds9 to display X. ds9 v5.2 or newer needs to be running.
Syntax
sao X [, min, max] [, /log, /zscale]
Arguments
X: A 2-dimensional matrix
min, max: Minimum and maximum array value for display scaling
Switches
/log: display the image in logarithmic scaling.
/zscale: Use a display representation similar to IRAF's zscale.
*/
void dpuserProcedure_sao(dpuserType arg0, dpString option1, dpString option2) {
    checkProcArgs("sao", arg0);

    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (xpa == NULL) {
        if ((xpa = XPAOpen(NULL)) == NULL) {
            throw dpuserTypeException("Can't open socket to image display server.");
        }
    }

    int nx = 0, ny = 0, ret = 0;
    char *names[NXPA];
    char *messages[NXPA];

    nx = arg0.fvalue->Naxis(1);
    ny = arg0.fvalue->Naxis(2);

    dpString accessPoint = "array [xdim=" + dpString::number(nx) +
                           ",ydim=" + dpString::number(ny) +
                           ",bitpix=" + dpString::number(arg0.fvalue->membits) + "]";

    ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                 (char*)arg0.fvalue->dataptr, nx * ny * (abs(arg0.fvalue->membits) / 8),
                 names, messages, NXPA);

    if (option1 == "log") {
        ret = XPASet(xpa, xpaServer, "scale log", NULL,
                     NULL, 0, names, messages, NXPA);
    } else {
        ret = XPASet(xpa, xpaServer, "scale linear", NULL,
                     NULL, 0, names, messages, NXPA);
    }

    if (option2 == "zscale") {
        ret = XPASet(xpa, xpaServer, "scale zscale", NULL,
                     NULL, 0, names, messages, NXPA);
    } else {
        ret = XPASet(xpa, xpaServer, "scale minmax", NULL,
                     NULL, 0, names, messages, NXPA);
    }

    /* error processing */
    for(int i = 0; i < ret; i++){
        if(messages[i]) {
            dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
        }
        if(names[i]) {
            free(names[i]);
        }
        if(messages[i]) {
            free(messages[i]);
        }
    }
}

//Alex
void dpuserProcedure_sao(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpString option1, dpString option2) {
    checkProcArgs("sao", arg0, arg1, arg2);

    if (ds9_running() == 0) {
        throw dpuserTypeException("ERROR: No ds9 is running! Please start first ds9 (at least v5.2)\n");
    }
    if (xpa == NULL) {
        if ((xpa = XPAOpen(NULL)) == NULL) {
            throw dpuserTypeException("Can't open socket to image display server.");
        }
    }

    int nx = 0, ny = 0, ret = 0;
    char *names[NXPA];
    char *messages[NXPA];

    nx = arg0.fvalue->Naxis(1);
    ny = arg0.fvalue->Naxis(2);

    dpString accessPoint = "array [xdim=" + dpString::number(nx) +
                           ",ydim=" + dpString::number(ny) +
                           ",bitpix=" + dpString::number(arg0.fvalue->membits) + "]";

    ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                 (char*)arg0.fvalue->dataptr, nx * ny * (abs(arg0.fvalue->membits) / 8),
                 names, messages, NXPA);

    if (option1 == "log") {
        ret = XPASet(xpa, xpaServer, "scale log", NULL,
                     NULL, 0, names, messages, NXPA);
    } else {
        ret = XPASet(xpa, xpaServer, "scale linear", NULL,
                     NULL, 0, names, messages, NXPA);
    }

    if (option2 == "zscale") {
        ret = XPASet(xpa, xpaServer, "scale zscale", NULL,
                     NULL, 0, names, messages, NXPA);
        dp_output(">>> min/max-values have been omitted, since zscale-option has been specified!\n");
    } else {
        accessPoint = "scale limits "  + dpString::number(arg1.dvalue) + " " + dpString::number(arg2.dvalue);
        ret = XPASet(xpa, xpaServer, (char*)accessPoint.c_str(), NULL,
                 NULL, 0, names, messages, NXPA);
    }

    /* error processing */
    for(int i = 0; i < ret; i++){
        if(messages[i]) {
            dp_output("ERROR: %s (%s)\n", messages[i], names[i]);
        }
        if(names[i]) {
            free(names[i]);
        }
        if(messages[i]) {
            free(messages[i]);
        }
    }
}

/*!
cirrange
Reduce a number to the range [0,360[ or [0,pi[.
Syntax
cirrange VAR [, /deg, /rad]
Arguments
VAR: A named variable whose value should be reduced. This can be a real number or a vector/matrix.
Switches
/deg: Reduce to [0,360[ (default)
/rad: Reduce to [0,pi[
*/

void dpuserProcedure_cirrange(dpuserType &arg, dpString option) {
    checkProcArgs("cirrange", arg);

    dpuserType range;
    long n = 0;
    range.type = typeDbl;
    range.dvalue = 360.;
    if (option == "rad") range.dvalue = 2. * M_PI;

    arg = dpuserFunction_modulo(arg, range);
    switch (arg.type) {
        case typeFits:
            for (n = 0; n < arg.fvalue->Nelements(); n++) {
                if ((*arg.fvalue)[n] < 0.) arg.fvalue->setValue((*arg.fvalue)[n] + range.dvalue, n+1, 1);
            }
        break;
        case typeCon:
            if (arg.lvalue < 0) arg.lvalue += 360;
            break;
        case typeDbl:
            if (arg.dvalue < 0.) arg.dvalue += range.dvalue;
            break;
        default:
            break;
    }
}

#if 0

/*!
swapaxes
Swap axes of a 3D array
Syntax
swapaxes VAR, newx, newy, newz
Arguments
VAR: A named variable which contains a 3D FITS
newx: Integer numer (1..3) which tells which axis shall become the X axis
newy: Integer numer (1..3) which tells which axis shall become the Y axis
newz: Integer numer (1..3) which tells which axis shall become the Z axis
Notes
The following FITS header keys are updated, if they exist:<br>
CRVAL, CRPIX, CDELT, CD matrix, CTYPE, CUNIT
Examples
OSIRIS 3D data come in the format [lambda,x,y]. To convert this to [x,y,lambda]:
<code>swapaxes buffer, 2, 3, 1
*/

void dpuserProcedure_swapaxes(dpuserType arg0, dpuserType arg1, dpuserType arg2, dpuserType arg3) {
    checkProcArgs("swapaxes", arg0, arg1, arg2, arg3);
    variables[arg0.toInt()].fvalue->swapaxes(arg1.toInt(), arg2.toInt(), arg3.toInt());
}

//TODO
/*!
debug
Turn on or off debug information.
Syntax
debug mode
Arguments
mode: An integer number. 0 means debugging information off, any other number display debugging information.
*/

//TODO
/*!
copyheader
Copy the FITS header from one matrix to another
Syntax
copyheader VAR, source
Arguments
VAR: A named variable of type fits which should receive the FITS header
source: The matrix with the FITS header to be copied
*/

//TODO
/*!
setfitstype
Set the (FITS extension) type info of given fits to either image or bintable
Syntax
setfitstype VAR [, extension], [ /image, /bintable]
Arguments
VAR: A named variable which contains a FITS, a FITS list, or a string array
extension: Optional in case of a FITS list, which element to set
Switches
/image: set the FITS type to image
/bintable: set the FITS type to bintable
*/

//TODO
/*!
watchdir
Watch a directory and trigger an action when a new file matching given pattern is created (only available on QFitsView). The remove the watch, call the procedure with empty arguments
Syntax
watchdir directory, pattern, action
Arguments
directory: A string specifying the directory to watch
pattern: A string, the file pattern to be matched
action: A string, the dpuser script to be executed. The file name is marked as $$
Examples
To trigger reading the first extension of a FITS file when created in /tmp:
<code>watchdir "/tmp", "*.fits", "hhh=readfitsextension($$, 1)"
Stop watching:
<code>watchdir "", "", ""
*/

//TODO
/*!
message
Print out a message on the terminal, or open a dialog box with the message in QFitsView
Syntax
message text [, /information | /warning | /critical]
Arguments
text: The message text to be displayed
Switches
the switch determines which icon to be displayed in the message box
*/

//TODO
/*!
python
Either enter PYTHON mode or execute given argument as PYTHON script
Syntax
python [script]
Arguments
script: A string with the script to execute
Examples
To print the integer number 10 using python:
<code>python "print(10)"
To define a simple function as python module, callable then from DPUSER:
<code>python "def add(a,b): return a+b"
<code>print add(2,2)
*/

//TODO
/*!
deletefitskey
Delete a FITS key in the header.
Syntax
deletefitskey fits x, string key
See also
function_getfitskey
procedure_setfitskey
*/

#endif
