Callout - how to get something beyond simple datatype (or return several datatypes)

Is there a way to get one of:

  • Struct
  • $lb
  • Subscripted local variable
  • List/array

As a return type from callout call?

And related question: is there a way to return several values (which may contain commas) from one callout call.  Or rather what's the best approach when doing that?

Consider the following example:

#define ZF_DLL
#include "cdzf.h"
#include <stdio.h>

int GetTwoStrings(char* a, char* b, char* retval) {
    sprintf(b,"%s",a);
    sprintf(retval,"%s",a);
    return ZF_SUCCESS; 
}

ZFBEGIN
   ZFENTRY("GetTwoStrings","1c1C1C",GetTwoStrings)
ZFEND

And the corresponding Caché code:

ClassMethod GetTwoStrings(a) As %String
{
    set b=""
    set path = "libsimplecallout.dll"
    set retval = $ZF(-3, path, "GetTwoStrings", a, b)
    zw a, b, retval
}

When I execute GetTwoStrings I get the following output:

do ..GetTwoStrings("my,Text")
a="my,Text"
b=""
retval="my,Text,my,Text"

retval returned from callout call contains both b and retval from C, but what's the best approach on parsing it into separate variables?

  • 0
  • 0
  • 140
  • 3
  • 1

Answers

JSON format is probably the most general. Return the values in a JSON formatted string. Then parse with

    SET objresult=##CLASS(%DynamicObject).%FromJSON(result)

However, if you want to return a simple structure. That is two or a few values, where no values are themselves structures, and nature of the data is easily understood, you could return the values as an artificial local reference, and take the value apart with $QSUBSCRIPT() is COS. This function would prove handy for such an option.

/* This function adds %q to snprintf() to print a quoted string. */
int varcosreturn (char *buffer, size_t len, char *fmt, ...) {
   va_list ap;
   char *p, *q, *r;
   char c;
   size_t n;
   char xfmt [3];

   va_start(ap, fmt);
   p = buffer; q = fmt;
   for (;;) {
      c = *q++;
      if (c == '\0') break;
      if (c != '%') { if (len==0) break; --len; *p++ = c; continue; }
      c = *q++;
      if (c == 'q') {
         if (len==0) break; --len; *p++ = '\"';
         r = va_arg(ap,char*);
         for (;;) {
            c = *r++;
            if (c == '\0') break;
            if (c == '\"') { if (len==0) break; --len; *p++ = '\"'; }
            if (len==0) break; --len; *p++ = c;
         }
         if (len==0) break; --len; *p++ = '\"';
         continue;
      }
      xfmt [0] = '%'; xfmt [1] = c; xfmt [2] ='\0';
      n = snprintf (p, len, xfmt, va_arg(ap, void*));
      len -= n; p += n;
   }
   va_end(ap);
   if (len==0) return -1; --len; *p++ = '\0';
   return 0;
}

$LISTBUID() format is not doucmented so that InterSystems can later expand (or change) it.

 

Thank you!

Can you please add these functions:

  • va_start
  • va_arg
  • va_end

To the above code:

#Include <stdio.h> /* For snprintf. */

#include <stdarg.h> /* For va_start, va_arg, and va_end. */

Comments

I'm not an expert on callout but deep back in history I believe to remember that what ever you
transfer is in wider sense a single item. If string structured by $p() or $lb().
You my take a closer look to %XML.SAX.* classes.
The highest structure is $LB(). Which is a string under cover.
And take care of the 32k limit