Written by

Senior Cloud Architect at InterSystems
MOD
Question Eduard Lebedyuk · Nov 29, 2017

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?

Comments

Robert Cemper · Nov 29, 2017

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 

0
Eduard Lebedyuk  Nov 30, 2017 to Stuart Salzer

Thank you!

Can you please add these functions:

  • va_start
  • va_arg
  • va_end
0
Stuart Salzer  Dec 6, 2017 to Stuart Salzer

To the above code:

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

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

0
Stuart Salzer · Nov 30, 2017

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.

0