📄 xmlrpc_introspection.c
字号:
return xParam;}/* convert an xml tree conforming to spec <url tbd> to XMLRPC_VALUE * suitable for use with XMLRPC_ServerAddIntrospectionData */XMLRPC_VALUE xml_element_to_method_description(xml_element* el, XMLRPC_ERROR err) { XMLRPC_VALUE xReturn = NULL; if(el->name) { const char* name = NULL; const char* type = NULL; const char* basetype = NULL; const char* desc = NULL; const char* def = NULL; int optional = 0; xml_element_attr* attr_iter = Q_Head(&el->attrs); /* grab element attributes up front to save redundant while loops */ while(attr_iter) { if(!strcmp(attr_iter->key, "name")) { name = attr_iter->val; } else if(!strcmp(attr_iter->key, "type")) { type = attr_iter->val; } else if(!strcmp(attr_iter->key, "basetype")) { basetype = attr_iter->val; } else if(!strcmp(attr_iter->key, "desc")) { desc = attr_iter->val; } else if(!strcmp(attr_iter->key, "optional")) { if(attr_iter->val && !strcmp(attr_iter->val, "yes")) { optional = 1; } } else if(!strcmp(attr_iter->key, "default")) { def = attr_iter->val; } attr_iter = Q_Next(&el->attrs); } /* value and typeDescription behave about the same */ if(!strcmp(el->name, "value") || !strcmp(el->name, "typeDescription")) { XMLRPC_VALUE xSubList = NULL; const char* ptype = !strcmp(el->name, "value") ? type : basetype; if(ptype) { if(Q_Size(&el->children) && (!strcmp(ptype, "array") || !strcmp(ptype, "struct") || !strcmp(ptype, "mixed"))) { xSubList = XMLRPC_CreateVector("member", xmlrpc_vector_array); if(xSubList) { xml_element* elem_iter = Q_Head(&el->children); while(elem_iter) { XMLRPC_AddValueToVector(xSubList, xml_element_to_method_description(elem_iter, err)); elem_iter = Q_Next(&el->children); } } } xReturn = describeValue_worker(ptype, name, (desc ? desc : (xSubList ? NULL : el->text.str)), optional, def, xSubList); } } /* these three kids are about equivalent */ else if(!strcmp(el->name, "params") || !strcmp(el->name, "returns") || !strcmp(el->name, "signature")) { if(Q_Size(&el->children)) { xml_element* elem_iter = Q_Head(&el->children); xReturn = XMLRPC_CreateVector(!strcmp(el->name, "signature") ? NULL : el->name, xmlrpc_vector_struct); while(elem_iter) { XMLRPC_AddValueToVector(xReturn, xml_element_to_method_description(elem_iter, err)); elem_iter = Q_Next(&el->children); } } } else if(!strcmp(el->name, "methodDescription")) { xml_element* elem_iter = Q_Head(&el->children); xReturn = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); XMLRPC_VectorAppendString(xReturn, xi_token_name, name, 0); while(elem_iter) { XMLRPC_AddValueToVector(xReturn, xml_element_to_method_description(elem_iter, err)); elem_iter = Q_Next(&el->children); } } /* items are slightly special */ else if(!strcmp(el->name, "item")) { xReturn = XMLRPC_CreateValueString(name, el->text.str, el->text.len); } /* sure. we'll let any ol element with children through */ else if(Q_Size(&el->children)) { xml_element* elem_iter = Q_Head(&el->children); xReturn = XMLRPC_CreateVector(el->name, xmlrpc_vector_mixed); while(elem_iter) { XMLRPC_AddValueToVector(xReturn, xml_element_to_method_description(elem_iter, err)); elem_iter = Q_Next(&el->children); } } /* or anything at all really, so long as its got some text. * no reason being all snotty about a spec, right? */ else if(el->name && el->text.len) { xReturn = XMLRPC_CreateValueString(el->name, el->text.str, el->text.len); } } return xReturn;}/*-***************************** End Introspection Utilities *******************************//*-******************* Introspection API *********************//****f* VALUE/XMLRPC_IntrospectionCreateDescription * NAME * XMLRPC_IntrospectionCreateDescription * SYNOPSIS * XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) * FUNCTION * converts raw xml describing types and methods into an * XMLRPC_VALUE suitable for use with XMLRPC_ServerAddIntrospectionData() * INPUTS * xml - xml data conforming to introspection spec at <url tbd> * err - optional pointer to error struct. filled in if error occurs and not NULL. * RESULT * XMLRPC_VALUE - newly created value, or NULL if fatal error. * BUGS * Currently does little or no validation of xml. * Only parse errors are currently reported in err, not structural errors. * SEE ALSO * XMLRPC_ServerAddIntrospectionData () * SOURCE */XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) { XMLRPC_VALUE xReturn = NULL; xml_element* root = xml_elem_parse_buf(xml, 0, 0, err ? &err->xml_elem_error : NULL); if(root) { xReturn = xml_element_to_method_description(root, err); xml_elem_free(root); } return xReturn;}/*******//****f* SERVER/XMLRPC_ServerAddIntrospectionData * NAME * XMLRPC_ServerAddIntrospectionData * SYNOPSIS * int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) * FUNCTION * updates server with additional introspection data * INPUTS * server - target server * desc - introspection data, should be a struct generated by * XMLRPC_IntrospectionCreateDescription () * RESULT * int - 1 if success, else 0 * NOTES * - function will fail if neither typeList nor methodList key is present in struct. * - if method or type already exists, it will be replaced. * - desc is never freed by the server. caller is responsible for cleanup. * BUGS * - horribly slow lookups. prime candidate for hash improvements. * - uglier and more complex than I like to see for API functions. * SEE ALSO * XMLRPC_ServerAddIntrospectionData () * XMLRPC_ServerRegisterIntrospectionCallback () * XMLRPC_CleanupValue () * SOURCE */int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) { int bSuccess = 0; if(server && desc) { XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList"); XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList"); XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList"); if(xNewMethods) { XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods); while(xMethod) { const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name); server_method* sm = find_method(server, name); if(sm) { if(sm->desc) { XMLRPC_CleanupValue(sm->desc); } sm->desc = XMLRPC_CopyValue(xMethod); bSuccess = 1; } xMethod = XMLRPC_VectorNext(xNewMethods); } } if(xNewTypes) { if(!xServerTypes) { if(!server->xIntrospection) { server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct); } XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes); bSuccess = 1; } else { XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes); while(xIter) { /* get rid of old values */ XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name)); if(xPrev) { XMLRPC_VectorRemoveValue(xServerTypes, xPrev); } XMLRPC_AddValueToVector(xServerTypes, xIter); bSuccess = 1; xIter = XMLRPC_VectorNext(xNewTypes); } } } } return bSuccess;}/*******//****f* SERVER/XMLRPC_ServerRegisterIntrospectionCallback * NAME * XMLRPC_ServerRegisterIntrospectionCallback * SYNOPSIS * int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) * FUNCTION * registers a callback for lazy generation of introspection data * INPUTS * server - target server * cb - callback that will generate introspection data * RESULT * int - 1 if success, else 0 * NOTES * parsing xml and generating introspection data is fairly expensive, thus a * server may wish to wait until this data is actually requested before generating * it. Any number of callbacks may be registered at any time. A given callback * will only ever be called once, the first time an introspection request is * processed after the time of callback registration. * SEE ALSO * XMLRPC_ServerAddIntrospectionData () * XMLRPC_IntrospectionCreateDescription () * SOURCE */int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) { int bSuccess = 0; if(server && cb) { doc_method* dm = calloc(1, sizeof(doc_method)); if(dm) { dm->method = cb; dm->b_called = 0; if(Q_PushTail(&server->docslist, dm)) { bSuccess = 1; } else { my_free(dm); } } } return 0;}/*******//*-*********************** End Introspection API *************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -