Lists and Other Dynamically Allocated Data

The resbuf structure includes a pointer field, rbnext, for linking result buffers into a list. Result buffers can be allocated statically by declaring them in the application. You do this when only a single result buffer is used (for example, by acedGetVar() and acedSetVar()) or when only a short list is needed. But longer lists are easier to handle by allocating them dynamically, and lists returned by ObjectARX functions are always allocated dynamically. One of the most frequently used functions that returns a linked list is acedGetArgs().

Evaluating External Functions shows the AutoLISP calling format of an external subroutine that takes arguments of three distinct types: a string, an integer, and a real value:

(doit pstr iarg rarg)

The following code segment shows how to implement a function with such a calling sequence. The sample function checks that the argument list is correct and saves the values locally before operating on them (operations are not shown). The example assumes that a previous call to acedDefun() has assigned the external subroutine a function code of 0, and that all functions defined by this application take at least one argument:

// Execute a defined function.  
int dofun() 
{ 
    struct resbuf *rb; 
    char str[64]; 
    int ival, val; 
    ads_real rval; 
    ads_point pt; 
// Get the function code.  
    if ((val = acedGetFuncode()) == RTERROR) 
        return BAD; // Indicate failure.  
    // Get the arguments passed in with the function.  
    if ((rb = acedGetArgs()) == NULL) 
        return BAD; 
    switch (val) { // Which function is called?  
    case 0: // (doit)  
        if (rb->restype != RTSTR) { 
            acutPrintf("\nDOIT called with %d type.", 
                rb->restype); 
            acutPrintf("\nExpected a string."); 
            return BAD; 
        } 
// Save the value in local string.  
        strcpy(str, rb->resval.rstring); 
// Advance to the next result buffer.  
        rb = rb->rbnext; 
        if (rb == NULL) { 
            acutPrintf("\nDOIT: Insufficient number of 
                arguments."); 
            return BAD; 
        } 
        if (rb->restype != RTSHORT) { 
            acutPrintf("\nDOIT called with %d type.", 
                rb->restype); 
            acutPrintf("\nExpected a short integer."); 
            return BAD; 
        } 
// Save the value in local variable.  
        ival = rb->resval.rint; 
// Advance to the last argument.  
        rb = rb->rbnext; 
        if (rb == NULL) { 
            acutPrintf("\nDOIT: Insufficient number of 
                arguments."); 
            return BAD; 
        } 
        if (rb->restype != RTREAL) { 
            acutPrintf("\nDOIT called with %d type.", 
                rb->restype); 
            acutPrintf("\nExpected a real."); 
            return BAD; 
        } 
// Save the value in local variable.  
        rval = rb->resval.rreal; 
// Check that it was the last argument. 
        if (rb->rbnext != NULL) { 
                acutPrintf("\nDOIT: Too many arguments."); 
            return BAD; 
        } 
// Operate on the three arguments.  
        . . . 
        return GOOD;  // Indicate success  
        break; 
    case 1: 
// Execute other functions. 
        . . . 
    } 
} 
Note: This example is exceptional in one respect: acedGetArgs() is the only ObjectARX global function that returns a linked list that the application does not have to explicitly release. The following section describes the usual way of managing the memory needed for lists.