File: PsychScriptingGlue.c

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (433 lines) | stat: -rw-r--r-- 19,688 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/*
 * PsychSourceGL/Source/Common/Base/PsychScriptingGlue.c
 *
 * AUTHORS:
 *
 * Allen.Ingling@nyu.edu        awi
 * mario.kleiner.de@gmail.com   mk
 *
 * PLATFORMS: All -- Glue layer to the runtime environment. Runtime environment independent parts.
 *
 * HISTORY:
 * 05/07/06   mk    Derived from Allen's PsychScriptingGlue
 * 11/08/06   mk    Fixes for Matlab beta on IntelMac -- Replace mxGetPr() by mxGetData()
 *                  or mxGetScalar() in places where this is appropriate. Using mxGetPr()
 *                  in the debug-build of the Matlab beta triggers an assertion when
 *                  passing a non-double array to mxGetPr().
 *
 * DESCRIPTION:
 *
 * ScriptingGlue defines abstracted functions to pass values
 * between the calling scripting environment and the PsychToolbox.
 *
 * NOTES:
 *
 * About default arguments:  In previous versions of the Psychtoolbox any matrix of size m*n=0
 * stood for the the "default" matrix.  When passed as an argument, it indicated that the
 * default value for that argument should be used.  This is useful when "omitting" intervening
 * arguments.
 *
 * Because each SCREEN subfunction interpreted arguments independently the ambiguities which
 * are discussed below did not have to be addressed but in the subfunctions which they arrose.
 * (which might be none).  The introduction of abstracted functions in ScriptingGlue mandates
 * a uniform policy for resloving ambiguities.
 *
 * Sometimes we want to pass an argument of size 0x0 and mean argument of size 0x0, not the
 * default matrix.  So ScriptingGlue functions which retrieve input arguments can not safetly
 * interpret an empty matrix as the default matrix.
 *
 * The problem is not as bad as it seems, because we can pass an empty
 * numerical matrix, "[]" when a string argument is expected, or pass an empty string "''" when
 * a numerical argument is expected.  Only in the case when an argument may be either a string or a number,
 * and 0 size arguments of both types are meaningful do we have a problem.  The case does not seem likely ever
 * to arise.
 *
 * For users, having two default arguments, '' and [],  and having to decide which to use depending on the
 * type of argument accepted, complicates the use of default arguments unpleasantly.  Furthermore, empty strings
 * are meaninful as strings, but empty numerical matrices are rarely meaninful as matrices. (why is that?)
 * Therefore, the best policy for ScriptingGlue functions would be: ScriptingGlue  functions which
 * retrieve string arguments will only interpret [] as the default matrix and will interpret '' as
 * the empty string.  ScriptingGlue functions which retrieve numerical arguments will accept either
 * [] or '' to be the empty string.
 *
 * So [] when passed for a number is always interpreted as the default matrix,
 * [] is the only value which stands for default when passed for a string,  Therefore, we can
 * reduce this further and accept only [] to stand for default, simplifing the users's decision of when to
 * use '' and when to use [], by ALWAYS using [].
 *
 * So in conclusion:
 * -[] and only [] means the default matrix.
 * -If you want a user to pass [] to mean a 0x0 matrix, too bad, you can't do that.
 * All ScriptingGlue functions will report that the argument was not present if the user
 * passes [].
 *
 */

// During inclusion of Psych.h, we define the special flag PTBINSCRIPTINGGLUE. This
// will cause some of the system headers in Psych.h not to be included during build
// of PsychScriptingGlue.c:
#define PTBINSCRIPTINGGLUE 1
#include "Psych.h"
#undef PTBINSCRIPTINGGLUE

////Static functions local to ScriptingGlue.c.
// _____________________________________________________________________________________

void InitializeSynopsis(char *synopsis[],int maxStrings);

#define MAX_SYNOPSIS 100
#define MAX_CMD_NAME_LENGTH 100

//Static variables local to ScriptingGlue.c.  The convention is to append a abbreviation in all
//caps of the C file name to the variable name.

static psych_bool subfunctionsEnabledGLUE = FALSE;

// Forward declaration for GNU/Linux compile:
#ifdef __cplusplus
    extern "C" void ScreenCloseAllWindows(void);
#else
    void ScreenCloseAllWindows(void);
#endif

/*
 *  functions for enabling and testing subfunction mode
 */
void PsychEnableSubfunctions(void)
{
    subfunctionsEnabledGLUE = TRUE;
}


psych_bool PsychAreSubfunctionsEnabled(void)
{
    return(subfunctionsEnabledGLUE);
}


PsychError PsychSetSpecifiedArgDescriptor(int                       position,
                                          PsychArgDirectionType     direction,
                                          PsychArgFormatType        type,
                                          PsychArgRequirementType   isRequired,
                                          psych_int64               mDimMin,        // minimum minimum is 1   |
                                          psych_int64               mDimMax,        // minimum maximum is 1, maximum maximum is -1 meaning infinity
                                          psych_int64               nDimMin,        // minimum minimum is 1   |
                                          psych_int64               nDimMax,        // minimum maximum is 1, maximum maximum is -1 meaning infinity
                                          psych_int64               pDimMin,        // minimum minimum is 0
                                          psych_int64               pDimMax)        // minimum maximum is 0, maximum maximum is -1 meaning infinity
{
    PsychArgDescriptorType d;

    // Check size of output dimensions if this is an output operation:
    if (direction == PsychArgOut) {
        // Do not exceed index size limits of hw/os/build architecture,
        // be it 32 bit or 64 bit:
        if (((size_t) mDimMin > SIZE_MAX) || ((size_t) mDimMax > SIZE_MAX) ||
            ((size_t) nDimMin > SIZE_MAX) || ((size_t) nDimMax > SIZE_MAX) ||
            ((size_t) pDimMin > SIZE_MAX) || ((size_t) pDimMax > SIZE_MAX)) {

            printf("PTB-ERROR: Tried to return a vector or matrix whose size along at least one dimension\n");
            printf("PTB-ERROR: exceeds the maximum supported number of elements.\n");

            if (sizeof(size_t) == 4) {
                printf("PTB-ERROR: This is a limitation of all 32 bit versions of Psychtoolbox.\n");
                printf("PTB-ERROR: You'd need to use a Psychtoolbox for 64-bit Matlab or 64-bit Octave\n");
                printf("PTB-ERROR: on a 64-bit operating system to get rid of this limit.\n");
            }

            PsychErrorExitMsg(PsychError_user, "One of the dimensions of a returned matrix or vector exceeds maximum number of elements. This is not supported on your setup!");
        }

        // Limits ok for given hw/os/build architecture. Check if they're ok for the
        // scripting environment as well:
        PsychCheckSizeLimits((size_t) mDimMin, (size_t) nDimMin, (size_t) pDimMin);
        PsychCheckSizeLimits((size_t) mDimMax, (size_t) nDimMax, (size_t) pDimMax);
    }

    d.position = position;
    d.direction = direction;
    d.type = type;
    // d.isThere                //field set only in the received are descriptor, not in the specified argument descriptor
    d.isRequired = isRequired;  //field set only in the specified arg descritor, not in the received argument descriptot.
    d.mDimMin = mDimMin;
    d.mDimMax = mDimMax;
    d.nDimMin = nDimMin;
    d.nDimMax = nDimMax;
    d.pDimMin = pDimMin;
    d.pDimMax = pDimMax;

    //NOTE that we are not setting the d.numDims field because that is inferred from pDimMin and pDimMax and the 3 dim cap.
    PsychStoreArgDescriptor(&d,NULL);
    return(PsychError_none);
}


/*
 *    PsychAcceptInputArgumentDecider()
 *
 *    This is a subroutine of Psychtoolbox functions such as PsychCopyInDoubleArg() which read in arguments to Psychtoolbox functino
 *    passed from the scripting environment.
 *
 *    Accept one constant specifying whether an argument is either required, optional, or anything will be allowed and another constant
 *    specifying how the provided argument agrees with the specified argument.  Based on the relationship between those constants either:
 *
 *        * Return TRUE indicating that the caller should read in the argument and itself return TRUE to indicate that the argument has been read.
 *        * Return FALSE indicating that the caller should ignore the argument and itself return FALSE to indicate that the argument was not read.
 *        * Exit to the calling environment with an error to indicate that the provided argument did not match the requested argument and that
 *          it was required to match.
 *
 *    The domain of supplied arguments is:
 *
 *    matchError:
 *        PsychError_internal                  -Internal Psychtoolbox error
 *        PsychError_invalidArg_absent         -There was no argument provided
 *        PsychError_invalidArg_type           -The argument was present but not the specified type
 *        PsychError_invalidArg_size           -The argument was presnet and the specified type but not the specified size
 *        PsychError_none                      -The argument matched the specified argument
 *
 *    isRequired:
 *        kPsychArgRequired                    - the argument must be present and must match the specified descriptor
 *        kPsychArgOptional                    - the argument must either be absent or must be present and match the specified descriptor
 *        kPsychArgAnything                    - the argument can be absent or anything
 *
 */
psych_bool PsychAcceptInputArgumentDecider(PsychArgRequirementType isRequired, PsychError matchError)
{
    if (isRequired==kPsychArgRequired) {
        if (matchError)
            PsychErrorExit(matchError);
        else
            return(TRUE);
    } else if (isRequired==kPsychArgOptional) {
        if (matchError==PsychError_invalidArg_absent)
            return(FALSE);
        else if (matchError)
            PsychErrorExit(matchError);
        else
            return(TRUE);
    } else if (isRequired==kPsychArgAnything) {
        if (!matchError)
            return(TRUE);
        else if (matchError==PsychError_invalidArg_absent)
            return(FALSE);
        else if (matchError==PsychError_invalidArg_type)
            return(FALSE);
        else if (matchError==PsychError_invalidArg_size)
            return(FALSE);
        else
            PsychErrorExit(matchError);
    }
    PsychErrorExitMsg(PsychError_internal, "Reached end of function unexpectedly");
    return(FALSE);            //make the compiler happy
}


/*
 *
 *    PsychAcceptOutputArgumentDecider()
 *
 *    This is a subroutine of Psychtoolbox functions such as PsychCopyCopyDoubleArg() which output arguments from Psychtoolbox functions
 *    back to the scripting environment.
 *
 */
psych_bool PsychAcceptOutputArgumentDecider(PsychArgRequirementType isRequired, PsychError matchError)
{
    if (isRequired==kPsychArgRequired) {
        if (matchError)
            PsychErrorExit(matchError);                     //the argument was required and absent so exit with an error. Or there was some other error.
        else
            return(TRUE);                                   //the argument was required and present so go read it.
    } else if (isRequired==kPsychArgOptional) {
        if (!matchError)
            return(TRUE);                                   //the argument was optional and present so go read it.
        else if (matchError==PsychError_invalidArg_absent)
            return(FALSE);                                  //the argument as optional and absent so dont' read  it.
        else if (matchError)
            PsychErrorExit(matchError);                     //there was some other error
    } else if (isRequired==kPsychArgAnything)
        PsychErrorExitMsg(PsychError_internal, "kPsychArgAnything argument passed to an output function.  Use kPsychArgOptional");
    else
        PsychErrorExit(PsychError_internal);

    PsychErrorExitMsg(PsychError_internal, "End of function reached unexpectedly");
    return(FALSE);        //make the compiler happy
}


/*
 *    PsychMatchDescriptors()
 *
 *    Compare descriptors for specified and received arguments. Return a mismatch error if they are
 *    incompatible, otherwise return a no error.
 *
 *    PsychMatchDescriptors compares:
 *        The argument type
 *        The argument size
 *        Argument presense
 *
 *    PsychMatchDescripts can return any of the following values describing the relationship between an
 *    argument provided from the scripting environment and argument requested by a Psychtoolbox module:
 *        PsychError_internal               -Internal Psychtoolbox error
 *        PsychError_invalidArg_absent      -There was no argument provided
 *        PsychError_invalidArg_type        -The argument was present but not the specified type
 *        PsychError_invalidArg_size        -The argument was presnet and the specified type but not the specified size
 *        PsychError_none                   -The argument matched the specified argument
 *
 *    This function should be enhnaced to report the nature of the disagrement
 */
PsychError PsychMatchDescriptors(void)
{
    PsychArgDescriptorType *specified, *received;

    PsychGetArgDescriptor(&specified, &received);

    //check for various bogus conditions resulting only from Psychtoolbox bugs and issue an internal error.
    if (specified->position != received->position)
        PsychErrorExit(PsychError_internal);
    if (specified->direction != received->direction)
        PsychErrorExit(PsychError_internal);

    if (specified->direction==PsychArgOut) {
        if (received->isThere==kPsychArgPresent || received->isThere==kPsychArgFixed)
            return(PsychError_none);
        else
            return(PsychError_invalidArg_absent);
    }
    if (specified->direction==PsychArgIn) {
        if (received->isThere==kPsychArgAbsent)
            return(PsychError_invalidArg_absent);
        //otherwise the argument is present and we proceed to the argument type and size checking block below
    }

    //if we get to here it means that an input argument was supplied.  Check if it agrees in type and size with the specified arg and return
    // an error type accordingly
    if (!(specified->type & received->type))
        return(PsychError_invalidArg_type);
    if (received->mDimMin != received->mDimMax || received->nDimMin != received->nDimMax ||  received->pDimMin != received->pDimMax)
        PsychErrorExit(PsychError_internal);    //unnecessary mandate
        if (received->mDimMin < specified->mDimMin)
            return(PsychError_invalidArg_size);
        if (received->nDimMin < specified->nDimMin)
            return(PsychError_invalidArg_size);
        if (specified->pDimMin != kPsychUnusedArrayDimension && received->pDimMin < specified->pDimMin)
            return(PsychError_invalidArg_size);
        if (specified->mDimMax != kPsychUnboundedArraySize && received->mDimMax > specified->mDimMax)
            return(PsychError_invalidArg_size);
        if (specified->nDimMax != kPsychUnboundedArraySize && received->nDimMax > specified->nDimMax)
            return(PsychError_invalidArg_size);
        if (specified->pDimMax != kPsychUnusedArrayDimension && specified->pDimMax != kPsychUnboundedArraySize && received->pDimMax > specified->pDimMax)
            return(PsychError_invalidArg_size);
        if (received->numDims > 3)  //we don't allow matrices with more than 3 dimensions.
            return(PsychError_invalidArg_size);

        //if we get to here it means that  the block above it means
        return(PsychError_none);
}


//functions for project access to module call arguments
//___________________________________________________________________________________________


//functions which query the number and nature of supplied arguments
PsychError PsychCapNumInputArgs(int maxInputs)
{
    if (PsychGetNumInputArgs() > maxInputs)
        return(PsychError_extraInputArg);
    else
        return(PsychError_none);
}


PsychError PsychRequireNumInputArgs(int minInputs)
{
    if (PsychGetNumInputArgs() < minInputs)
        return(PsychError_missingInputArg);
    else
        return(PsychError_none);
}


/*
 *    The argument is present if anything was supplied, including the default matrix
 */
psych_bool PsychIsArgReallyPresent(PsychArgDirectionType direction, int position)
{
    return(direction == PsychArgOut ? PsychGetNumOutputArgs() >= position : PsychGetNumInputArgs() >= position);
}


/*
 *    PsychCheckInputArgType()
 *
 *    Check that the input argument at the specifid position matches at least one of the types passed in the argType
 *    argument. If the argument violates the proscription exit with an error.  Otherwise return a psych_bool indicating
 *    whether the argument was present.
 */
psych_bool PsychCheckInputArgType(int position, PsychArgRequirementType isRequired, PsychArgFormatType argType)
{
    PsychError      matchError;
    psych_bool      acceptArg;

    PsychSetReceivedArgDescriptor(position, FALSE, PsychArgIn);
    PsychSetSpecifiedArgDescriptor(position, PsychArgIn, argType, isRequired, 0,kPsychUnboundedArraySize,0,kPsychUnboundedArraySize,0,kPsychUnboundedArraySize);
    matchError=PsychMatchDescriptors();
    acceptArg=PsychAcceptInputArgumentDecider(isRequired, matchError);
    return(acceptArg);
}


/*functions with input arguments.
 * ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 * ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 */

/*
 * A)input argument mandatory:
 *
 *    1)input argument not present:         exit with error.
 *    2)input argument present:             set *array to the input matrix, *m, *n, and *p to its dimensions, return TRUE.
 * B)input argument optional:
 *
 *    1)input argument not present:         return FALSE
 *    2)input argument present:             set *array to the input matrix, *m, *n, and *p to its dimensions, return TRUE.
 *
 */

/*
 *    PsychAllocOutFlagListArg()
 *
 *    This seems silly.  Find out where its used and consider using an array of booleans instead.  Probably the best thing
 *    is just to transparently map arrays of booleans to logical arrays MATLAB.
 *
 *    In Matlab our psych_bool flags are actually doubles.  This will not be so in all scripting languages.  We disguise the
 *    implementation of psych_bool flags within the scripting envrironment by making the flag list opaque and
 *    providing accessor fucntions PsychLoadFlagListElement, PsychSetFlagListElement, and PsychClearFlagListElement.
 *
 *    TO DO: maybe this should return a logical array instead of a bunch of doubles.  Itwould be better for modern versions
 *    of MATLAB which store doubles as bytes internally.
 *
 *
 */
psych_bool PsychAllocOutFlagListArg(int position, PsychArgRequirementType isRequired, int numElements, PsychFlagListType *flagList)
{
    return(PsychAllocOutDoubleMatArg(position, isRequired, (int)1, numElements, (int)0, flagList));
}


void PsychLoadFlagListElement(int index, psych_bool value, PsychFlagListType flagList)
{
    flagList[index]=(double)value;
}


void PsychSetFlagListElement(int index, PsychFlagListType flagList)
{
    flagList[index]=(double)1;
}


void PsychClearFlagListElement(int index, PsychFlagListType flagList)
{
    flagList[index]=(double)0;
}