PageRenderTime 52ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/XML/XML/src/Utils.c

#
C | 413 lines | 252 code | 84 blank | 77 comment | 26 complexity | 13037cd5446805f08cf2656588523dd2 MD5 | raw file
  1. /**
  2. Routines that are shared across the two XML parsers and their callbacks
  3. to R.
  4. isBlank - determines if a string consists entirely of whitespace
  5. RS_XML(invokeFunction) - call a user-level function, previously located
  6. by RS_XML(findFunction).
  7. RS_XML(findFunction) - search a list or closure for a function object
  8. with a given name in that list.
  9. * See Copyright for the license status of this software.
  10. */
  11. #include "Utils.h"
  12. #include <ctype.h> /* For isspace() */
  13. #ifdef LIBXML
  14. #ifdef FROM_GNOME_XML_DIR
  15. #include <gnome-xml/parser.h>
  16. #else
  17. #include <libxml/parser.h>
  18. #endif
  19. #endif
  20. #include "RSCommon.h" /* for SET_NAMES */
  21. /**
  22. Tests whether the string contains only white space
  23. or not. Returns 1 if is only white space. 0 otherwise.
  24. */
  25. int isBlank(const char *str)
  26. {
  27. int blank=0;
  28. const char *ptr = str;
  29. while(ptr && (blank = isspace(ptr[0]))) {
  30. ptr++;
  31. }
  32. return(blank);
  33. }
  34. /**
  35. Does an in place trimming of a string by returning a pointer
  36. to the first non-white space character and also inserting a
  37. string terminator after the last non-whitespace character.
  38. */
  39. char *
  40. trim(char *str)
  41. {
  42. char *tmp;
  43. /* If a degenerate string, just return. */
  44. if(str == (char*)NULL || str[0] == '\0')
  45. return(str);
  46. /* Jumpt to the end */
  47. tmp = str + strlen(str) - 1;
  48. while(tmp >= str && isspace(*tmp)) {
  49. tmp[0] = '\0';
  50. tmp--;
  51. }
  52. if(tmp == str) {
  53. #if 0
  54. if(strlen(tmp) > 1)
  55. tmp[0] = '\0';
  56. #endif
  57. return(str);
  58. }
  59. #if 0
  60. else
  61. tmp[1] = '\0';
  62. #endif
  63. tmp = str;
  64. while(*tmp && isspace(*tmp)) {
  65. tmp++;
  66. }
  67. return(tmp);
  68. }
  69. USER_OBJECT_
  70. RS_XML(treeApply)(USER_OBJECT_ rtree, USER_OBJECT_ function, USER_OBJECT_ args)
  71. {
  72. return(rtree);
  73. }
  74. /**
  75. Error handling utilities for use with the libxml document parsing mechanism.
  76. Intercept the error handling by replacing it with a routine of the same name
  77. and have it print to a buffer. Then call the Warning handler. Then the warnings
  78. will end up in the local system, accessible via the warnings() function.
  79. This allows them to be programmatically processed rather than having to process
  80. the output to the terminal (via catching it in a call sink()).
  81. */
  82. #ifdef LIBXML
  83. #include <stdarg.h>
  84. void localXmlParserPrintFileInfo(xmlParserInputPtr input, char *buf);
  85. #ifndef USE_LINKED_ERROR_HANDLER
  86. void S_xmlParserError(void *ctx, const char *msg, ...)
  87. #else
  88. void xmlParserError(void *ctx, const char *msg, ...)
  89. #endif
  90. {
  91. va_list args;
  92. #if 1
  93. va_start(args, msg);
  94. stop("XMLParserError", msg, args);
  95. #else
  96. xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
  97. char buf[3000], *tmp;
  98. /* Empty the string buffer. */
  99. memset(buf , '\0', sizeof(buf)/sizeof(buf[0]));
  100. /* Insert the file and line number. */
  101. localXmlParserPrintFileInfo(ctxt->input, buf);
  102. /* Move to the end of the buffer's contents. */
  103. tmp = buf + strlen(buf);
  104. va_start(args, msg);
  105. /* Write in the actual message. */
  106. vsprintf(tmp, msg, args);
  107. va_end(args);
  108. PROBLEM "XML Parsing Error: %s", buf
  109. WARN;
  110. #endif
  111. }
  112. #ifndef USE_LINKED_ERROR_HANDLER
  113. /*
  114. Set the default error handlers in the libxml library
  115. */
  116. void
  117. RSXML_setErrorHandlers()
  118. {
  119. xmlDefaultSAXHandlerInit();
  120. htmlDefaultSAXHandlerInit();
  121. #if 0
  122. docbDefaultSAXHandlerInit();
  123. #endif
  124. xmlDefaultSAXHandler.error = S_xmlParserError;
  125. htmlDefaultSAXHandler.error = S_xmlParserError;
  126. #if 0
  127. docbDefaultSAXHandler.error = S_xmlParserError;
  128. #endif
  129. }
  130. #endif
  131. /**
  132. Write the file name and the current line number into the specified
  133. string.
  134. */
  135. void localXmlParserPrintFileInfo(xmlParserInputPtr input, char *buf) {
  136. if (input != NULL) {
  137. if (input->filename)
  138. sprintf(buf, "%s:%d: ", input->filename,
  139. input->line);
  140. else
  141. sprintf(buf, "Entity: line %d: ", input->line);
  142. }
  143. }
  144. #endif
  145. /**
  146. Utility method for setting the names of a list/vector from an array of
  147. native strings rather than an R/S character vector structure.
  148. */
  149. void
  150. RS_XML(SetNames)(int n, const char *cnames[], USER_OBJECT_ ans)
  151. {
  152. int i;
  153. USER_OBJECT_ names;
  154. PROTECT(names = NEW_CHARACTER(n));
  155. for(i = 0; i < n ; i++) {
  156. /* could install as a pre-defined string. */
  157. SET_STRING_ELT(names, i, mkChar(cnames[i]));
  158. }
  159. SET_NAMES(ans, names);
  160. UNPROTECT(1);
  161. }
  162. /*
  163. Set the class of the target object to be the character vector containing
  164. just the specified name.
  165. */
  166. int
  167. RS_XML(SetClassName)(const char *localClassName, USER_OBJECT_ target)
  168. {
  169. USER_OBJECT_ className;
  170. PROTECT(className = NEW_CHARACTER(1));
  171. SET_STRING_ELT(className, 0, mkChar(localClassName));
  172. SET_CLASS(target, className);
  173. UNPROTECT(1);
  174. return(1);
  175. }
  176. #if LIBXML2
  177. struct _xmlHashTable {
  178. struct _xmlHashEntry **table;
  179. int size;
  180. };
  181. #endif
  182. #if OWN_XML_HASH_SIZE
  183. int xmlHashSize(xmlHashTablePtr table)
  184. {
  185. /* For version 2.2.* */
  186. return(table->size);
  187. /*
  188. return(table->nb_entities);
  189. */
  190. }
  191. #endif
  192. USER_OBJECT_
  193. RS_XML(findFunction)(const char *opName, USER_OBJECT_ _userObject)
  194. {
  195. int i;
  196. USER_OBJECT_ fun = NULL;
  197. /* Get the names of the list. */
  198. USER_OBJECT_ names = GET_NAMES(_userObject);
  199. /* lookup function in the names of the list */
  200. for (i = 0; i < GET_LENGTH(names); i++) {
  201. if(!strcmp(opName, CHAR_DEREF(STRING_ELT(names, i)))) {
  202. fun = VECTOR_ELT(_userObject, i);
  203. break;
  204. }
  205. }
  206. return(fun);
  207. }
  208. SEXP
  209. R_makeRefObject(void *ref, const char *className)
  210. {
  211. SEXP klass, obj, sref;
  212. if(!ref) {
  213. PROBLEM "NULL value for external reference"
  214. WARN;
  215. return(R_NilValue);
  216. }
  217. PROTECT(klass = MAKE_CLASS((char *) className)); /* XXX define MAKE_CLASS with const */
  218. if(klass == R_NilValue) { /* Is this the right test? */
  219. PROBLEM "Cannot find class %s for external reference", className
  220. ERROR;
  221. }
  222. PROTECT(obj = NEW_OBJECT(klass));
  223. PROTECT(sref = R_MakeExternalPtr(ref, Rf_install(className), R_NilValue));
  224. obj = SET_SLOT(obj, Rf_install("ref"), sref);
  225. UNPROTECT(3);
  226. return(obj);
  227. }
  228. #include <libxml/uri.h>
  229. #define copyStrField(x) SET_VECTOR_ELT(ans, i, mkString(uri->x ? uri->x : "")); \
  230. SET_STRING_ELT(names, i, mkChar(#x)); i++;
  231. SEXP
  232. R_parseURI(SEXP r_uri)
  233. {
  234. xmlURIPtr uri;
  235. SEXP ans, names;
  236. int i= 0;
  237. uri = xmlParseURI( CHAR( STRING_ELT( r_uri, 0 )));
  238. if(!uri) {
  239. PROBLEM "cannot parse URI %s", CHAR( STRING_ELT( r_uri, 0) )
  240. ERROR;
  241. }
  242. PROTECT(ans = NEW_LIST(8));
  243. PROTECT(names = NEW_CHARACTER(8));
  244. copyStrField(scheme);
  245. copyStrField(authority);
  246. copyStrField(server);
  247. copyStrField(user);
  248. copyStrField(path);
  249. copyStrField(query);
  250. copyStrField(fragment);
  251. SET_VECTOR_ELT(ans, i, ScalarInteger(uri->port));
  252. SET_STRING_ELT(names, i, mkChar("port"));
  253. SET_NAMES(ans, names);
  254. UNPROTECT(2);
  255. return(ans);
  256. }
  257. #define min(x, y) ((x) < (y) ? (x) : (y))
  258. SEXP
  259. RSXML_structuredStop(SEXP errorFun, xmlErrorPtr err)
  260. {
  261. SEXP e, ptr;
  262. int n = 8;
  263. if(!err)
  264. n = 2;
  265. PROTECT(e = allocVector(LANGSXP, 8));
  266. SETCAR(e, errorFun != NULL && errorFun != R_NilValue ? errorFun : Rf_install("xmlStructuredStop"));
  267. ptr = CDR(e);
  268. if(err) {
  269. SETCAR(ptr, mkString(err->message));
  270. ptr= CDR(ptr);
  271. SETCAR(ptr, ScalarInteger(err->code));
  272. ptr= CDR(ptr);
  273. SETCAR(ptr, ScalarInteger(err->domain));
  274. ptr= CDR(ptr);
  275. SETCAR(ptr, ScalarInteger(err->line));
  276. ptr= CDR(ptr);
  277. SETCAR(ptr, ScalarInteger(err->int2));
  278. ptr= CDR(ptr);
  279. SETCAR(ptr, ScalarInteger(err->level));
  280. ptr= CDR(ptr);
  281. SETCAR(ptr, err->file ? mkString(err->file) : NEW_CHARACTER(0));
  282. } else {
  283. SETCAR(ptr, NEW_CHARACTER(0));
  284. }
  285. Rf_eval(e, R_GlobalEnv);
  286. UNPROTECT(1);
  287. /* Shouldn't get back to here! Rf_eval() should raise an error.*/
  288. return(R_NilValue);
  289. }
  290. /*
  291. Because we call this function via Rf_eval(), we end up
  292. with an extra call on the stack when we enter recover.
  293. */
  294. SEXP
  295. stop(const char *className, const char *msg, ...)
  296. {
  297. char buf[10000];
  298. SEXP error, e, ns_env, ns_name;
  299. va_list ap;
  300. va_start(ap, msg);
  301. /* Rvsnprintf(buf, sizeof(buf)/sizeof(buf[0]), msg, ap); */
  302. vsnprintf(buf, sizeof(buf)/sizeof(buf[0]), msg, ap);
  303. va_end(ap);
  304. PROTECT(error = mkString(buf));
  305. /*
  306. const char * classNames[] = {"simpleError", "error", "condition"};
  307. PROTECT(tmp = allocVector(STRSXP, sizeof(classNames)/sizeof(classNames[0])));
  308. for(i = 0; i < sizeof(classNames)/sizeof(classNames[0]); i++)
  309. SET_STRING_ELT(tmp, i+1, mkChar(classNames[i]));
  310. SET_STRING_ELT(tmp, 0, mkChar(className));
  311. SET_CLASS(error, tmp);
  312. */
  313. PROTECT(e = allocVector(LANGSXP, 2));
  314. PROTECT(ns_name = mkString("XML"));
  315. ns_env = R_FindNamespace(ns_name);
  316. SETCAR(e, findVarInFrame(ns_env, Rf_install("xmlStop")));
  317. SETCAR(CDR(e), error);
  318. Rf_eval(e, R_GlobalEnv);
  319. UNPROTECT(2);
  320. /*
  321. errorcall(error, "%s", msg);
  322. UNPROTECT(1);
  323. */
  324. return(error);
  325. }