C++ COFFEE API, argument passing



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/07/2012 at 10:23, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R12 
    Platform:      
    Language(s) :

    ---------
    I'm testing a little bit with the COFFEE API. It first appeared like a bug to me, but now my question: Are you guys seriously reversing the arguments the user passed via a function?

    Some code and calling-examples:

    void CoffeeExtension_printf(Coffee* engine, VALUE*& argv, LONG argc) {  
      GePrint("CoffeeExtension_printf() :");  
      for (int i=0; i < argc; i++) {  
          char buffer[100];  
          sprintf(buffer, "  Type of argument %d:   %d", i, argv[i].GetType());  
          GePrint(buffer);  
      }  
      GePrint("");  
      
      if (argc < 1) {  
          engine->SetError(COFFEEERROR_ARGW, "Expected at least one argument.");  
          goto nil;  
      }  
      
      VALUE* vformat = argv;  
      
      if (!vformat->IsType(DT_STRING)) {  
          engine->SetError(COFFEEERROR_BTYP, "Expected first argument to be string.");  
          goto nil;  
      }  
      
      goto continue_;  
      
      nil:  
      // Coffee-Return nil.  
      argv[argc].SetNil();  
      argv += argc;  
      return;  
      
      continue_:  
      /** **/  
      ;  
    }  
      
    Bool RegisterCoffeeExtensions() {  
      Coffee* engine = GetCoffeeMaster();  
      if (!engine) {  
          return FALSE;  
      }  
      
      engine->AddGlobalFunction("printf", CoffeeExtension_printf);  
      return TRUE;  
    }
    

    When I call printf in COFFEE now, I get the following:

    [IN ]: printf("foo bar spam egg");  
    [OUT]:  
    CoffeeExtension_printf() :  
      Type of argument 0:   6
    

    Fine, DT_STRING has a value of 6.

    [IN ]: printf("foo bar", 5, 10, 9.0);  
    [OUT]:  
    CoffeeExtension_printf() :  
      Type of argument 0:   2  
      Type of argument 1:   1  
      Type of argument 2:   1  
      Type of argument 3:   6
    

    This isn't fine. DT_FLOAT is 2, DT_LONG is 3 and DT_STRING is 6.

    Why are the arguments in reverse order?

    Thanks,
    -Nik



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/07/2012 at 11:45, xxxxxxxx wrote:

    Possibly reflects the way in which arguments are passed to the COFFEE engine. Looks like a LIFO stack. So the last argument to go on the stack (the float) is the first to be pulled off, the string is the last one to be pulled off.

    Maxon support should be able to confirm.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 10/07/2012 at 12:27, xxxxxxxx wrote:

    @spedler: Thanks for your answer. I just got curious because I haven't seen it that way, yet. And I thought it may be just an issue of mine and I just did something wrone while getting the values.

    Nevermind, here's a little code that implements a very very small printf() function in COFFEE. :)

    // coding: utf-8  
    // author: Niklas Rosenstein  
    //  
    // This program is free software: you can redistribute it and/or modify  
    // it under the terms of the GNU General Public License as published by  
    // the Free Software Foundation, either version 3 of the License, or  
    // (at your option) any later version.  
    //  
    // This program is distributed in the hope that it will be useful,  
    // but WITHOUT ANY WARRANTY; without even the implied warranty of  
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
    // GNU General Public License for more details.  
      
    #include <c4d/c4d.h>  
      
    Bool RegisterCoffeeExtensions();  
      
    // COFFEE Extension Functions  
    void CoffeeExtension_printf(Coffee* engine, VALUE*& argv, LONG argc);
    
    // coding: utf-8  
    // author: Niklas Rosenstein  
    //  
    // This program is free software: you can redistribute it and/or modify  
    // it under the terms of the GNU General Public License as published by  
    // the Free Software Foundation, either version 3 of the License, or  
    // (at your option) any later version.  
    //  
    // This program is distributed in the hope that it will be useful,  
    // but WITHOUT ANY WARRANTY; without even the implied warranty of  
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
    // GNU General Public License for more details.  
    //  
    // You should have received a copy of the GNU General Public License  
    // along with this program.  If not, see <http://www.gnu.org/licenses/>  
      
    #include "coffeeext.h"  
    #include <stdio.h>  
    #include <c4d/c4d.h>  
      
    static String VALUEToString(VALUE* val, Bool& success);  
      
    Bool RegisterCoffeeExtensions() {  
      Coffee* engine = GetCoffeeMaster();  
      if (!engine) {  
          return FALSE;  
      }  
      
      engine->AddGlobalFunction("printf", CoffeeExtension_printf);  
      return TRUE;  
    }  
      
    void CoffeeExtension_printf(Coffee* engine, VALUE*& argv, LONG argc) {  
      // The function accepts at least one argument. The first argument should  
      // be string formatted like C-style printf. All following arguments  
      // will be inserted into the string.  
      // Possible format sequences are:  
      //  
      //  %s:     String  
      //  %%:     Escape for Percent character.  
      
      if (argc < 1) {  
          engine->SetError(COFFEEERROR_ARGW, "Expected at least one argument.");  
          goto nil;  
      }  
      
      // Somehow, the passed arguments are in reverse order.. -.-  
      VALUE* vformat = argv + argc - 1;  
      
      if (!vformat->IsType(DT_STRING)) {  
          engine->SetError(COFFEEERROR_BTYP, "Expected first argument to be string.");  
          goto nil;  
      }  
      
      goto continue_;  
      
      nil:  
      // Coffee-Return nil.  
      argv[argc].SetLong(0);  
      argv += argc;  
      return;  
      
      continue_:  
      
      char    buffer[80];  
      String  format = vformat->GetString();  
      LONG    format_length = format.GetLength();  
      String  destination = "";  
      int     curr_arg = argc - 2;  
      VALUE*  curr_val = NULL;  
      
      for (int i=0; i < format_length; i++) {  
          char character = format[i];  
          if (character == '%') {  
              i++;  
              if (!(i < format_length)) {  
                  destination += String("%");  
                  goto nil;  
              }  
              char fmt = format[i];  
              if (fmt == '%') {  
                  destination += "%";  
              }  
              else {  
                  curr_val = &argv[curr_arg];  
                  Bool success;  
                  if (fmt == 's') {  
                      destination += VALUEToString(curr_val, success);  
                  }  
                  else {  
                      sprintf(buffer, "Unsupported format character %c!", fmt);  
                      engine->SetError(COFFEEERROR_BTYP, String(buffer));  
                      goto nil;  
                  }  
                  curr_arg--;  
              }  
          }  
          else {  
              destination += String(1, format[i]);  
          }  
      }  
      GePrint(destination);  
      
      argv[argc].SetLong(1);  
      argv += argc;  
      return;  
    }  
      
      
    static String VALUEToString(VALUE* val, Bool& success) {  
      LONG type = val->GetType();  
      success = TRUE;  
      
      Vector v;  
      char buffer[20];  
      String final;  
      LONG count;  
      switch (type) {  
          case DT_NIL:  
              return String("nil");  
          case DT_LONG:  
              return LongToString(val->GetLong());  
          case DT_FLOAT:  
              return RealToString(val->GetReal());  
          case DT_VECTOR:  
              v = val->GetVector();  
              return "Vector(" + RealToString(v.x) + ", " + RealToString(v.y) +  
                     ", " + RealToString(v.z) + ")";  
          case DT_VOID:  
              sprintf(buffer, "0x%x", val->GetVoid());  
              return "[VOID at " + String(buffer) + "]";  
          case DT_BYTES:  
              return "[BYTES]";  
          case DT_STRING:  
              return val->GetString();  
          case DT_CLASS:  
              return "[CLASS]";  
          case DT_OBJECT:  
              sprintf(buffer, "0x%x", val->GetObject());  
              return "[OBJECT at " + String(buffer) + "]";  
          case DT_ARRAY:  
              final = "[";  
              count = val->GetSize();  
              for (int i=0; i < count; i++) {  
                  VALUE* subval = val->GetArrayMember(i);  
                  final += VALUEToString(subval, success) + ", ";  
                  if (!success) {  
                      return String();  
                  }  
              }  
              final += "]";  
              return final;  
          // case DT_NUMBER:  
          default:  
              success = FALSE;  
              return String();  
      }  
    }
    

    -Nik


Log in to reply