将“Tcl_Obj * const objv []”转换为“char ** argv”

时间:2016-12-09 04:11:19

标签: c++11 tcl

我正在使用Tcl 8.6,我正在尝试做这样的事情来向tcl解释器添加函数

Tcl_Interp* interp, 

void init() {
  interp = Tcl_CreateInterp();
}

void add_tcl_function(char* cmd, function<int(int,char**)> F) {
    obj2argv* o2a = new obj2argv;

    auto lambda_proc = [&](
        ClientData cdata, 
        Tcl_Interp* interp, 
        int objc, 
        Tcl_Obj* const objv[])
    {
       o2a->set(objc, objv);
       F(objc, o2a->get_argv());
    };

    auto lamba_delete = [&](
      delete o2a;
    };

    Tcl_CreateObjCommand(interp, cmd, lamda_proc, NULL, lamda_delete);
}

我想知道的是如何将“Tcl_Obj * const objv []”转换为“char ** argv”?

我在考虑创建一个类:

class obj2argv {
    obj2argv();
    void set(int objc, Tcl_Obj* const objv[]);
    char** get_argv();
private: 
  //...
};

关于如何实现set()和get_argv()的任何想法?

有更简单的方法吗?

感谢。

obj2argv* o2a = new obj2argv;

2 个答案:

答案 0 :(得分:2)

如果您正在为一个基本上与const char**一起使用的函数连接参数,那么您应该使用Tcl_CreateCommand注册该函数,并让Tcl为您处理字符串映射。它已经具备了所有必需的机制。

更正式地说,您正在处理具有此签名的粘合功能:

typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp,
        int argc, CONST84 char *argv[]);

CONST84应该在所有新代码中被视为普通const,而ClientData是一个指针大小的值,Tcl只是动手并且从不检查(与您的相同)现有代码)。

如果您要自己进行映射,Tcl_GetString将获取Tcl_Obj*并返回char*的表示形式。该表示通常应视为const;由于历史原因,它并没有正式输入。

答案 1 :(得分:0)

我想补充一些信息:

我放弃使用lambda&#39; s因为当我添加捕获列表时,由于某种原因它不能将lambda转换为函数指针。所以我选择了传统方法(见下文)。除了:我仍然不知道为什么TCL文件说

typedef int Tcl_CmdProc(
        ClientData clientData,
        Tcl_Interp *interp,
        int argc,
        const char *argv[]);

但是编译器需要这个来编译:

typedef int Tcl_CmdProc(
        ClientData clientData,
        Tcl_Interp *interp,
        int argc,
        Tcl_Obj*  const* argv);

守则:

int cmd_dispatch(
  ClientData   clientData,
  Tcl_Interp*  interp,
  int          argc,
  Tcl_Obj*  const* argv)
{
  function<int(int,char**)> F = *(function<int(int,char**)>*)clientData;

  return F(argc, (char**) argv);  // <= CAST DOESN'T SEEM RIGHT
}

void cmd_delete(ClientData clientData)
{

}

void add_tcl_function(const char* cmd, function<int(int,char**)> F) {

    Tcl_CreateObjCommand(interp, cmd, cmd_dispatch, (void*)&F, cmd_delete);

}

版本2:

struct cmd_data {
//Tcl_Interp*                interp,
  function<int(int,char**)>  F;
  int                        argc;
  char*                      argv[MAX_ARGS];
};

int cmd_dispatch(
  ClientData   clientData,
  Tcl_Interp*  interp,
  int          argc,
  Tcl_Obj*  const* objv)
{
  auto cmd_data1 = (struct cmd_data*) clientData;

  cmd_data1->argc = argc;
  for(int i=0; ((i < argc) && (i < MAX_ARGS)); i++) {
    cmd_data1->argv[i] = Tcl_GetString(objv[i]);
        // Who owns object returned by Tcl_GetString?
        //  memory leak? or invalid after return from function?
        // garbage collected by tcl interp? 
  }
  return cmd_data1->F(argc, cmd_data1->argv);
}

void cmd_delete(ClientData clientData)
{
  auto cmd_data1 = (struct cmd_data*) clientData;

  if (cmd_data1) {
    delete cmd_data1;
  }
}


void add_tcl_function(const char* cmd, function<int(int,char**)> F) {


    auto cmd_data1 = new struct cmd_data;
    cmd_data1->F = F;
    Tcl_CreateObjCommand(interp, cmd, cmd_dispatch, (void*)cmd_data1, cmd_delete);

}


void init_tcl_commands() {
    auto lambda_hello = [&](int argc ,char** argv) -> int {
        cout << "HELLO WORLD!\n";
        return 0;
    };

    tcl_backend::add_tcl_function("hello", lambda_hello);
}