luacurl源码阅读4 - ALL_CURL_OPT宏

luacurl.c文件定义处的ALL_CURL_OPT展开

/* wrap curl option with simple option type */
#define C_OPT(n, t)
/* wrap curl option with string list type */
#define C_OPT_SL(n) static const char* KEY_##n = #n;
/* wrap the other curl options not included above */
#define C_OPT_SPECIAL(n)


//因为C_OPT和C_OPT_SPECIAL都是空的,所以下面忽略了
/* describes all currently supported curl options available to curl 7.15.2 */
#define ALL_CURL_OPT \
    C_OPT_SL(HTTPHEADER) \ /* 相当于: static const char* KEY_HTTPHEADER = "HTTPHEADER"; */
    C_OPT_SL(HTTPPOST) \ /* 相当于: static const char* KEY_HTTPPOST = "HTTPPOST"; */
    C_OPT_SL(QUOTE) \ /* 相当于: static const char* KEY_QUOTE = "QUOTE"; */
    C_OPT_SL(POSTQUOTE) \ /* 相当于: static const char* KEY_POSTQUOTE = "POSTQUOTE"; */
    C_OPT_SL(TELNETOPTIONS) \ /* 相当于: static const char* KEY_TELNETOPTIONS = "TELNETOPTIONS"; */
    C_OPT_SL(PREQUOTE) \ /* 相当于: static const char* KEY_PREQUOTE = "PREQUOTE"; */
    C_OPT_SL(HTTP200ALIASES) \ /* 相当于: static const char* KEY_HTTP200ALIASES = "HTTP200ALIASES"; */
    C_OPT_SL(SOURCE_PREQUOTE) \ /* 相当于: static const char* KEY_SOURCE_PREQUOTE = "SOURCE_PREQUOTE"; */
    C_OPT_SL(SOURCE_POSTQUOTE) \ /* 相当于: static const char* KEY_SOURCE_POSTQUOTE = "SOURCE_POSTQUOTE"; */
    C_OPT_SL(SOURCE_QUOTE) \ /* 相当于: static const char* KEY_SOURCE_QUOTE = "SOURCE_QUOTE"; */

//......

ALL_CURL_OPT

 

lcurl_easy_setopt函数中的ALL_CURL_OPT展开

switch (curlOpt)
{
    //CURLOPT_XxxDATA和CURLOPT_XxxFUNCTION部分的case
    //......

/* Handle all supported curl options differently according the specific option argument type */
#undef C_OPT
#define C_OPT(n, t) \
    case CURLOPT_##n: \
        v=get_##t(L, 3); \
        break;

#undef C_OPT_SL
#define C_OPT_SL(n) \
    case CURLOPT_##n: \
    { \
        v=get_slist(L, 3, &KEY_##n); \
    }break;

/* Expands all the list of switch-case's here, 宏展开后, 就是剩余CURLOPT_Xxx的case */
ALL_CURL_OPT

    default:
        luaL_error(L, "Not supported curl option %d", curlOpt);
}

相当于

switch (curlOpt)
{
    case CURLOPT_URL: //对应 C_OPT(URL, string)
        v = get_string(L, 3);
        break;

    case CURLOPT_PORT: //对应 C_OPT(PORT, number)
        v = get_number(L, 3);
        break;

    case CURLOPT_HEADER: //对应 C_OPT(HEADER, boolean)
        v = get_boolean(L, 3);
        break;

    case CURLOPT_HTTPHEADER: //对应 C_OPT_SL(HTTPHEADER)
        v = get_slist(L, 3, &KEY_HTTPHEADER);
        break;

    case CURLOPT_HTTPPOST: //对应 C_OPT_SL(HTTPPOST)
        v = get_slist(L, 3, &KEY_HTTPPOST);
        break;

    //......

    default:
        luaL_error(L, "Not supported curl option %d", curlOpt);
}

下面的lua代码就会进入到ALL_CURL_OPT宏展开的case分支

local curl = require("libcurl")

local c = curl.new()

local headers = {}
table.insert(headers, "Authorization: Bearer sk-xxxxxxxxxxxxx");
table.insert(headers, "Content-Type: application/json");
c:setopt(curl.OPT_HTTPHEADER, unpack(headers))

 

get_slist函数 

/* after argument number n combine all arguments to the curl type curl_slist */
static union luaValueT get_slist(lua_State* L, int n, const char** key)
{
    printf("get_slist begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //4, userdata

    int i;
    union luaValueT v;
    struct curl_slist *slist=0;

    /* free the previous slist if any */
    free_slist(L, key);
    printf("get_slist 111: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //5, userdata

    /* check if all parameters are strings */
    for (i=n; i<lua_gettop(L); i++)
        luaL_checkstring(L, i);

    for (i=n; i<lua_gettop(L); i++)
    {
        slist = curl_slist_append(slist, lua_tostring(L, i));
    }

    /* set the new slist in registry */
    lua_pushlightuserdata(L, (void*)key);
    lua_pushlightuserdata(L, (void *)slist);
    lua_rawset(L, LUA_REGISTRYINDEX); //等同于: 栈[LUA_REGISTRYINDEX][name] = slist, 执行完后栈顶弹出2个元素, name="userdata: "..keyAddr

    v.slist=slist;

    printf("get_slist end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //5, userdata
    return v;
}

 

free_slist函数

/* remove and free old slist from registry if any associated with the given key */
static void free_slist(lua_State* L, const char** key)
{
    printf("free_slist begin: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //4, userdata

    struct curl_slist *slist;
    lua_pushlightuserdata(L, (void *)key); //变量地址压入栈顶
    lua_rawget(L, LUA_REGISTRYINDEX); //栈[LUA_REGISTRYINDEX][k]的元素压入栈顶, k的值为: "userdata: "..keyAddr
    printf("free_slist 111: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //5, userdata
    slist=(struct curl_slist *)lua_topointer(L, -1); //栈顶元素转换为指针
    if (slist)
    {
        curl_slist_free_all(slist);
    }

     printf("free_slist end: %d, %s\n", lua_gettop(L), lua_typename(L, lua_type(L, 1)) ); //5, userdata
}

 

lcurl_easy_close函数中的ALL_CURL_OPT展开

/* Finalizes CURL */
static int lcurl_easy_close(lua_State* L)
{
    //......

#undef C_OPT
#undef C_OPT_SL
#undef C_OPT_SPECIAL

#define C_OPT(n, t)
#define C_OPT_SL(n) free_slist(L, &KEY_##n);
#define C_OPT_SPECIAL(n)

    // 如果KEY_Xxx存放了对应的slist,则释放
    ALL_CURL_OPT

    //......
}

相当于

//......

free_slist(L, &KEY_HTTPHEADER)
free_slist(L, &KEY_HTTPPOST)
free_slist(L, &KEY_QUOTE)
free_slist(L, &KEY_POSTQUOTE)
free_slist(L, &KEY_TELNETOPTIONS)
free_slist(L, &KEY_PREQUOTE)
free_slist(L, &KEY_HTTP200ALIASES)
free_slist(L, &KEY_SOURCE_PREQUOTE)
free_slist(L, &KEY_SOURCE_POSTQUOTE)
free_slist(L, &KEY_SOURCE_QUOTE)

//......

 

posted @ 2025-07-06 14:07  yanghui01  阅读(5)  评论(0)    收藏  举报