| | 949 | struct xpath_iter { |
|---|
| | 950 | xmlXPathContextPtr ctxt; |
|---|
| | 951 | xmlXPathObjectPtr pobj; |
|---|
| | 952 | int cnt; |
|---|
| | 953 | int idx; |
|---|
| | 954 | }; |
|---|
| | 955 | static int |
|---|
| | 956 | noit_lua_xpath_iter(lua_State *L) { |
|---|
| | 957 | struct xpath_iter *xpi; |
|---|
| | 958 | xpi = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 959 | if(xpi->pobj) { |
|---|
| | 960 | if(xpi->idx < xpi->cnt) { |
|---|
| | 961 | xmlNodePtr node, *nodeptr; |
|---|
| | 962 | node = xmlXPathNodeSetItem(xpi->pobj->nodesetval, xpi->idx); |
|---|
| | 963 | xpi->idx++; |
|---|
| | 964 | nodeptr = (xmlNodePtr *)lua_newuserdata(L, sizeof(node)); |
|---|
| | 965 | *nodeptr = node; |
|---|
| | 966 | luaL_getmetatable(L, "noit.xmlnode"); |
|---|
| | 967 | lua_setmetatable(L, -2); |
|---|
| | 968 | return 1; |
|---|
| | 969 | } |
|---|
| | 970 | } |
|---|
| | 971 | return 0; |
|---|
| | 972 | } |
|---|
| | 973 | static int |
|---|
| | 974 | noit_lua_xpath(lua_State *L) { |
|---|
| | 975 | int n; |
|---|
| | 976 | const char *xpathexpr; |
|---|
| | 977 | xmlDocPtr *docptr, doc; |
|---|
| | 978 | xmlNodePtr *nodeptr = NULL; |
|---|
| | 979 | xmlXPathContextPtr ctxt; |
|---|
| | 980 | struct xpath_iter *xpi; |
|---|
| | 981 | |
|---|
| | 982 | n = lua_gettop(L); |
|---|
| | 983 | /* the first arg is implicitly self (it's a method) */ |
|---|
| | 984 | docptr = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 985 | if(docptr != lua_touserdata(L, 1)) |
|---|
| | 986 | luaL_error(L, "must be called as method"); |
|---|
| | 987 | if(n < 2 || n > 3) luaL_error(L, "expects 1 or 2 arguments, got %d", n); |
|---|
| | 988 | doc = *docptr; |
|---|
| | 989 | xpathexpr = lua_tostring(L, 2); |
|---|
| | 990 | if(!xpathexpr) luaL_error(L, "no xpath expression provided"); |
|---|
| | 991 | ctxt = xmlXPathNewContext(doc); |
|---|
| | 992 | if(n == 3) { |
|---|
| | 993 | nodeptr = lua_touserdata(L, 3); |
|---|
| | 994 | if(nodeptr) ctxt->node = *nodeptr; |
|---|
| | 995 | } |
|---|
| | 996 | if(!ctxt) luaL_error(L, "invalid xpath"); |
|---|
| | 997 | |
|---|
| | 998 | xpi = (struct xpath_iter *)lua_newuserdata(L, sizeof(*xpi)); |
|---|
| | 999 | xpi->ctxt = ctxt; |
|---|
| | 1000 | xpi->pobj = xmlXPathEval((xmlChar *)xpathexpr, xpi->ctxt); |
|---|
| | 1001 | if(!xpi->pobj || xpi->pobj->type != XPATH_NODESET) |
|---|
| | 1002 | xpi->cnt = 0; |
|---|
| | 1003 | else |
|---|
| | 1004 | xpi->cnt = xmlXPathNodeSetGetLength(xpi->pobj->nodesetval); |
|---|
| | 1005 | xpi->idx = 0; |
|---|
| | 1006 | luaL_getmetatable(L, "noit.xpathiter"); |
|---|
| | 1007 | lua_setmetatable(L, -2); |
|---|
| | 1008 | lua_pushcclosure(L, noit_lua_xpath_iter, 1); |
|---|
| | 1009 | return 1; |
|---|
| | 1010 | } |
|---|
| | 1011 | static int |
|---|
| | 1012 | noit_lua_xmlnode_attr(lua_State *L) { |
|---|
| | 1013 | xmlNodePtr *nodeptr; |
|---|
| | 1014 | /* the first arg is implicitly self (it's a method) */ |
|---|
| | 1015 | nodeptr = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 1016 | if(nodeptr != lua_touserdata(L, 1)) |
|---|
| | 1017 | luaL_error(L, "must be called as method"); |
|---|
| | 1018 | if(lua_gettop(L) == 2 && lua_isstring(L,2)) { |
|---|
| | 1019 | xmlChar *v; |
|---|
| | 1020 | const char *attr = lua_tostring(L,2); |
|---|
| | 1021 | v = xmlGetProp(*nodeptr, (xmlChar *)attr); |
|---|
| | 1022 | if(v) { |
|---|
| | 1023 | lua_pushstring(L, (const char *)v); |
|---|
| | 1024 | xmlFree(v); |
|---|
| | 1025 | } |
|---|
| | 1026 | else lua_pushnil(L); |
|---|
| | 1027 | return 1; |
|---|
| | 1028 | } |
|---|
| | 1029 | luaL_error(L,"must be called with no arguments"); |
|---|
| | 1030 | return 0; |
|---|
| | 1031 | } |
|---|
| | 1032 | static int |
|---|
| | 1033 | noit_lua_xmlnode_contents(lua_State *L) { |
|---|
| | 1034 | xmlNodePtr *nodeptr; |
|---|
| | 1035 | /* the first arg is implicitly self (it's a method) */ |
|---|
| | 1036 | nodeptr = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 1037 | if(nodeptr != lua_touserdata(L, 1)) |
|---|
| | 1038 | luaL_error(L, "must be called as method"); |
|---|
| | 1039 | if(lua_gettop(L) == 1) { |
|---|
| | 1040 | xmlChar *v; |
|---|
| | 1041 | v = xmlNodeGetContent(*nodeptr); |
|---|
| | 1042 | if(v) { |
|---|
| | 1043 | lua_pushstring(L, (const char *)v); |
|---|
| | 1044 | xmlFree(v); |
|---|
| | 1045 | } |
|---|
| | 1046 | else lua_pushnil(L); |
|---|
| | 1047 | return 1; |
|---|
| | 1048 | } |
|---|
| | 1049 | luaL_error(L,"must be called with no arguments"); |
|---|
| | 1050 | return 0; |
|---|
| | 1051 | } |
|---|
| | 1052 | static int |
|---|
| | 1053 | noit_lua_xmlnode_next(lua_State *L) { |
|---|
| | 1054 | xmlNodePtr *nodeptr; |
|---|
| | 1055 | nodeptr = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 1056 | if(*nodeptr) { |
|---|
| | 1057 | xmlNodePtr *newnodeptr; |
|---|
| | 1058 | newnodeptr = (xmlNodePtr *)lua_newuserdata(L, sizeof(*nodeptr)); |
|---|
| | 1059 | *newnodeptr = *nodeptr; |
|---|
| | 1060 | luaL_getmetatable(L, "noit.xmlnode"); |
|---|
| | 1061 | lua_setmetatable(L, -2); |
|---|
| | 1062 | *nodeptr = (*nodeptr)->next; |
|---|
| | 1063 | return 1; |
|---|
| | 1064 | } |
|---|
| | 1065 | return 0; |
|---|
| | 1066 | } |
|---|
| | 1067 | static int |
|---|
| | 1068 | noit_lua_xmlnode_children(lua_State *L) { |
|---|
| | 1069 | xmlNodePtr *nodeptr, node, cnode; |
|---|
| | 1070 | /* the first arg is implicitly self (it's a method) */ |
|---|
| | 1071 | nodeptr = lua_touserdata(L, lua_upvalueindex(1)); |
|---|
| | 1072 | if(nodeptr != lua_touserdata(L, 1)) |
|---|
| | 1073 | luaL_error(L, "must be called as method"); |
|---|
| | 1074 | node = *nodeptr; |
|---|
| | 1075 | cnode = node->children; |
|---|
| | 1076 | nodeptr = lua_newuserdata(L, sizeof(cnode)); |
|---|
| | 1077 | *nodeptr = cnode; |
|---|
| | 1078 | luaL_getmetatable(L, "noit.xmlnode"); |
|---|
| | 1079 | lua_setmetatable(L, -2); |
|---|
| | 1080 | lua_pushcclosure(L, noit_lua_xmlnode_next, 1); |
|---|
| | 1081 | return 1; |
|---|
| | 1082 | } |
|---|
| | 1083 | static int |
|---|
| | 1084 | noit_lua_xpathiter_gc(lua_State *L) { |
|---|
| | 1085 | struct xpath_iter *xpi; |
|---|
| | 1086 | xpi = lua_touserdata(L, 1); |
|---|
| | 1087 | xmlXPathFreeContext(xpi->ctxt); |
|---|
| | 1088 | if(xpi->pobj) xmlXPathFreeObject(xpi->pobj); |
|---|
| | 1089 | return 0; |
|---|
| | 1090 | } |
|---|
| | 1091 | static int |
|---|
| | 1092 | noit_xmlnode_index_func(lua_State *L) { |
|---|
| | 1093 | int n; |
|---|
| | 1094 | const char *k; |
|---|
| | 1095 | xmlNodePtr *udata, obj; |
|---|
| | 1096 | n = lua_gettop(L); /* number of arguments */ |
|---|
| | 1097 | assert(n == 2); |
|---|
| | 1098 | if(!luaL_checkudata(L, 1, "noit.xmlnode")) { |
|---|
| | 1099 | luaL_error(L, "metatable error, arg1 not a noit.xmlnode!"); |
|---|
| | 1100 | } |
|---|
| | 1101 | udata = lua_touserdata(L, 1); |
|---|
| | 1102 | obj = *udata; |
|---|
| | 1103 | if(!lua_isstring(L, 2)) { |
|---|
| | 1104 | luaL_error(L, "metatable error, arg2 not a string!"); |
|---|
| | 1105 | } |
|---|
| | 1106 | k = lua_tostring(L, 2); |
|---|
| | 1107 | switch(*k) { |
|---|
| | 1108 | case 'a': |
|---|
| | 1109 | if(!strcmp(k,"attr") || |
|---|
| | 1110 | !strcmp(k,"attribute")) { |
|---|
| | 1111 | lua_pushlightuserdata(L, udata); |
|---|
| | 1112 | lua_pushcclosure(L, noit_lua_xmlnode_attr, 1); |
|---|
| | 1113 | return 1; |
|---|
| | 1114 | } |
|---|
| | 1115 | break; |
|---|
| | 1116 | case 'c': |
|---|
| | 1117 | if(!strcmp(k,"children")) { |
|---|
| | 1118 | lua_pushlightuserdata(L, udata); |
|---|
| | 1119 | lua_pushcclosure(L, noit_lua_xmlnode_children, 1); |
|---|
| | 1120 | return 1; |
|---|
| | 1121 | } |
|---|
| | 1122 | if(!strcmp(k,"contents")) { |
|---|
| | 1123 | lua_pushlightuserdata(L, udata); |
|---|
| | 1124 | lua_pushcclosure(L, noit_lua_xmlnode_contents, 1); |
|---|
| | 1125 | return 1; |
|---|
| | 1126 | } |
|---|
| | 1127 | break; |
|---|
| | 1128 | default: |
|---|
| | 1129 | break; |
|---|
| | 1130 | } |
|---|
| | 1131 | luaL_error(L, "noit.xmlnode no such element: %s", k); |
|---|
| | 1132 | return 0; |
|---|
| | 1133 | } |
|---|
| | 1134 | static int |
|---|
| | 1135 | nl_parsexml(lua_State *L) { |
|---|
| | 1136 | xmlDocPtr *docptr, doc; |
|---|
| | 1137 | const char *in; |
|---|
| | 1138 | size_t inlen; |
|---|
| | 1139 | |
|---|
| | 1140 | if(lua_gettop(L) != 1) luaL_error(L, "parsexml requires one argument"); |
|---|
| | 1141 | |
|---|
| | 1142 | in = lua_tolstring(L, 1, &inlen); |
|---|
| | 1143 | doc = xmlParseMemory(in, inlen); |
|---|
| | 1144 | if(!doc) { |
|---|
| | 1145 | lua_pushnil(L); |
|---|
| | 1146 | return 1; |
|---|
| | 1147 | } |
|---|
| | 1148 | |
|---|
| | 1149 | docptr = (xmlDocPtr *)lua_newuserdata(L, sizeof(doc)); |
|---|
| | 1150 | *docptr = doc; |
|---|
| | 1151 | luaL_getmetatable(L, "noit.xmldoc"); |
|---|
| | 1152 | lua_setmetatable(L, -2); |
|---|
| | 1153 | return 1; |
|---|
| | 1154 | } |
|---|
| | 1155 | static int |
|---|
| | 1156 | noit_lua_xmldoc_gc(lua_State *L) { |
|---|
| | 1157 | xmlDocPtr *holder; |
|---|
| | 1158 | holder = (xmlDocPtr *)lua_touserdata(L,1); |
|---|
| | 1159 | xmlFreeDoc(*holder); |
|---|
| | 1160 | return 0; |
|---|
| | 1161 | } |
|---|
| | 1162 | static int |
|---|
| | 1163 | noit_xmldoc_index_func(lua_State *L) { |
|---|
| | 1164 | int n; |
|---|
| | 1165 | const char *k; |
|---|
| | 1166 | xmlDocPtr *udata, obj; |
|---|
| | 1167 | n = lua_gettop(L); /* number of arguments */ |
|---|
| | 1168 | assert(n == 2); |
|---|
| | 1169 | if(!luaL_checkudata(L, 1, "noit.xmldoc")) { |
|---|
| | 1170 | luaL_error(L, "metatable error, arg1 not a noit.xmldoc!"); |
|---|
| | 1171 | } |
|---|
| | 1172 | udata = lua_touserdata(L, 1); |
|---|
| | 1173 | obj = *udata; |
|---|
| | 1174 | if(!lua_isstring(L, 2)) { |
|---|
| | 1175 | luaL_error(L, "metatable error, arg2 not a string!"); |
|---|
| | 1176 | } |
|---|
| | 1177 | k = lua_tostring(L, 2); |
|---|
| | 1178 | switch(*k) { |
|---|
| | 1179 | case 'x': |
|---|
| | 1180 | if(!strcmp(k, "xpath")) { |
|---|
| | 1181 | lua_pushlightuserdata(L, udata); |
|---|
| | 1182 | lua_pushcclosure(L, noit_lua_xpath, 1); |
|---|
| | 1183 | return 1; |
|---|
| | 1184 | } |
|---|
| | 1185 | break; |
|---|
| | 1186 | default: |
|---|
| | 1187 | break; |
|---|
| | 1188 | } |
|---|
| | 1189 | luaL_error(L, "noit.xmldoc no such element: %s", k); |
|---|
| | 1190 | return 0; |
|---|
| | 1191 | } |
|---|