summaryrefslogtreecommitdiffstats
path: root/kxsldbg/kxsldbgpart/libxsldbg/files.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kxsldbg/kxsldbgpart/libxsldbg/files.cpp')
-rw-r--r--kxsldbg/kxsldbgpart/libxsldbg/files.cpp1420
1 files changed, 1420 insertions, 0 deletions
diff --git a/kxsldbg/kxsldbgpart/libxsldbg/files.cpp b/kxsldbg/kxsldbgpart/libxsldbg/files.cpp
new file mode 100644
index 0000000..73d3713
--- /dev/null
+++ b/kxsldbg/kxsldbgpart/libxsldbg/files.cpp
@@ -0,0 +1,1420 @@
+
+/***************************************************************************
+ files.h - define file related functions
+ -------------------
+ begin : Sat Nov 10 2001
+ copyright : (C) 2001 by Keith Isdale
+ email : k_isdale@tpg.com.au
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+/* We want skip most of these includes when building documentation */
+#ifndef BUILD_DOCS
+
+#include "xsldbg.h"
+#include <stdio.h>
+#include <libxml/entities.h>
+#include <libxml/tree.h>
+#include <libxml/catalog.h>
+#include <libxml/parserInternals.h>
+#include <libxml/encoding.h> /* needed by filesTranslate, filesEncoding functions */
+#include <libxml/uri.h> /* needed for xmlURIUnescapeString */
+#include "debugXSL.h"
+#include "files.h"
+#include "utils.h"
+#include "options.h"
+#include "xsldbgthread.h"
+#ifdef WIN32
+#include <direct.h>
+#endif
+
+#endif /* BUILD_DOCS */
+
+
+/* top xml document */
+static xmlDocPtr topDocument;
+
+/* temporary xml document */
+static xmlDocPtr tempDocument;
+
+/* used as a scratch pad for temporary results*/
+static xmlChar filesBuffer[DEBUG_BUFFER_SIZE];
+
+/* top stylsheet */
+static xsltStylesheetPtr topStylesheet;
+
+/* what is the base path for top stylesheet */
+static xmlChar *stylePathName = NULL;
+
+/* what is the path for current working directory*/
+static xmlChar *workingDirPath = NULL;
+
+static arrayListPtr entityNameList = NULL;
+
+/* Current encoding to use for standard output*/
+static xmlCharEncodingHandlerPtr stdoutEncoding = NULL;
+
+/* input and output buffers for encoding*/
+static xmlBufferPtr encodeInBuff = NULL;
+static xmlBufferPtr encodeOutBuff = NULL;
+
+/* Current line number and URI for xsldbg*/
+static int currentLineNo = -1;
+static xmlChar *currentUrl = NULL;
+
+/* -----------------------------------------
+ Private function declarations for files.c
+ -------------------------------------------*/
+
+/**
+ * guessStylesheetHelper:
+ * @payload: valid xsltStylesheetPtr
+ * @data: valid searchInfoPtr of type SEARCH_NODE
+ * @name: not used
+ *
+ * Try to guess what the complete file/URI is. If successful the search
+ * info will be set to found and the search data will contain the
+ * file name found. We are given our payload via walkStylesheets
+ */
+static void guessStylesheetHelper(void *payload, void *data,
+ xmlChar * name);
+
+
+/**
+ * guessStylesheetHelper2:
+ * @payload: valid xmlNodePtr of the included stylesheet
+ * @data: valid searchInfoPtr of type SEARCH_NODE
+ * @name: not used
+ *
+ * Try to guess what the complete file/URI is. If successful the search
+ * info will be set to found and the search data will contain the
+ * file name found. We are given our payload via walkIncludes
+ */
+static void guessStylesheetHelper2(void *payload, void *data,
+ xmlChar * name);
+
+
+entityInfoPtr filesNewEntityInfo(const xmlChar * SystemID,
+ const xmlChar * PublicID);
+
+void filesFreeEntityInfo(entityInfoPtr info);
+
+void filesAddEntityName(const xmlChar * SystemID,
+ const xmlChar * PublicID);
+
+
+/* -------------------------------------
+ End private functions
+---------------------------------------*/
+
+
+FILE *terminalIO;
+
+/* No longer needed
+ static FILE *oldStdin, *oldStdout, *oldStderr;*/
+
+
+//static char *ttyName = NULL; /* what is the name of the default terminal */
+static char *termName = NULL; /* what is the name of terminal we are redirected to */
+
+
+/**
+ * redirectToTerminal:
+ * @device: terminal to redirect i/o to , will not work under win32
+ *
+ * Open communications to the terminal device @device
+ *
+ * Returns 1 if sucessful
+ * 0 otherwise
+ */
+int
+openTerminal(xmlChar * device)
+{
+ int result = 0;
+
+ if (!device) { /* Failed; there's no device */
+#ifdef WITH_XSLDBG_DEBUG_PROCESS
+ xsltGenericError(xsltGenericErrorContext,
+ "Error: NULL argument provided\n");
+#endif
+ return result;
+ }
+
+ /*
+ * On RISC OS, you get one terminal - the screen.
+ * we assume that the parameter is meant to be an output device as
+ * per normal - we can use vdu:, rawvdu: or :tt, or a filename for
+ * normal VDU output, VDU output without newline expansion,
+ * C terminal output with control code escaping, or a raw file
+ * respectively.
+ * The name passed is expected to be in native file format - no
+ * URI escaping here.
+ * One assumes that you might use a socket or a pipe here.
+ */
+
+ if (terminalIO) {
+ fclose(terminalIO);
+ terminalIO = NULL;
+ }
+
+
+ switch (device[0]) {
+ case '\0':
+ case '0':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* look like we are supposed to close the terminal
+ * but we've already done that
+ */
+ break;
+
+ case '1':
+ if (termName) {
+ terminalIO = fopen((char *) termName, "w");
+ if (terminalIO != NULL) {
+ xmlFree(termName);
+ termName = xmlMemStrdup((char *) device);
+ result = 1;
+ } else {
+ xsldbgGenericErrorFunc(i18n("Error: Unable to open terminal %1.\n").arg(xsldbgText(termName)));
+ }
+ } else {
+ xsldbgGenericErrorFunc(i18n("Error: Did not previously open terminal.\n"));
+ }
+ break;
+
+ case '2':
+#ifdef WITH_XSLDBG_DEBUG_PROCESS
+ xsltGenericError(xsltGenericErrorContext,
+ "Warning: Terminal level 2 not implemented\n");
+#endif
+ break;
+
+
+ default:
+ terminalIO = fopen((char *) device, "w");
+ if (terminalIO != NULL) {
+ if (termName)
+ xmlFree(termName);
+ termName = xmlMemStrdup((char *) device);
+ result = 1;
+ } else {
+ xsldbgGenericErrorFunc(i18n("Error: Unable to open terminal %1.\n").arg(xsldbgText(device)));
+ }
+
+ }
+
+ return result;
+}
+
+
+/**
+ * guessStylesheetHelper:
+ * @payload: valid xsltStylesheetPtr
+ * @data: valid searchInfoPtr of type SEARCH_NODE
+ * @name: not used
+ *
+ * Try to guess what the complete file/URI is. If successful the search
+ * info will be set to found and the search data will contain the
+ * file name found. We are given our payload via walkStylesheets
+ */
+void
+guessStylesheetHelper(void *payload, void *data,
+ xmlChar * name)
+{
+ Q_UNUSED(name);
+ xsltStylesheetPtr style = (xsltStylesheetPtr) payload;
+ searchInfoPtr searchCriteria = (searchInfoPtr) data;
+ nodeSearchDataPtr searchData = NULL;
+ /* where did the directory/URI separator occur */
+ char *lastSlash;
+
+ if (!style || !style->doc || !searchCriteria || !searchCriteria->data
+ || (searchCriteria->type != SEARCH_NODE))
+ return;
+
+ searchData = (nodeSearchDataPtr) searchCriteria->data;
+ if (searchData->nameInput && (searchData->absoluteNameMatch == NULL)) {
+ /* at this point we know that we have not made an absolute match
+ * but we may have made a relative match */
+ if (xmlStrCmp(style->doc->URL, searchData->nameInput) == 0) {
+ /* absolute path match great! */
+ searchData->absoluteNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) style->doc->URL);
+ searchData->node = (xmlNodePtr) style->doc;
+ searchCriteria->found = 1;
+ return;
+ }
+
+
+ /* try to guess we assume that the files are unique */
+ xmlStrCpy(filesBuffer, "__#!__");
+ /* try relative to top stylesheet directory */
+ if (stylePath()) {
+ xmlStrCpy(filesBuffer, stylePath());
+ xmlStrCat(filesBuffer, searchData->nameInput);
+ }
+ if (xmlStrCmp(style->doc->URL, filesBuffer) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) filesBuffer);
+ searchData->node = (xmlNodePtr) style->doc;
+ searchCriteria->found = 1;
+ return;
+ }
+
+ if (workingPath()) {
+ /* try relative to working directory */
+ xmlStrCpy(filesBuffer, workingPath());
+ xmlStrCat(filesBuffer, searchData->nameInput);
+ }
+ if (xmlStrCmp(style->doc->URL, filesBuffer) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) filesBuffer);
+ searchData->node = (xmlNodePtr) style->doc;
+ searchCriteria->found = 1;
+ return;
+ }
+
+
+ /* Find the last separator of the stylsheet's URL */
+ lastSlash = xmlStrChr(style->doc->URL, URISEPARATORCHAR);
+ if (!lastSlash)
+ lastSlash = xmlStrChr(style->doc->URL, PATHCHAR);
+
+ if (lastSlash) {
+ /* Last try, assume nameInput contains only a file name
+ * Strip of the file name at end of the stylesheet doc URL */
+ lastSlash++; /* skip the slash */
+ if (xmlStrCmp(lastSlash, searchData->nameInput) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) style->doc->URL);
+ searchData->node = (xmlNodePtr) style->doc;
+ searchCriteria->found = 1;
+ }
+ }
+ }
+}
+
+
+/**
+ * guessStylesheetHelper2:
+ * @payload: valid xmlNodePtr of the included stylesheet
+ * @data: valid searchInfoPtr of type SEARCH_NODE
+ * @name: not used
+ *
+ * Try to guess what the complete file/URI is. If successful the search
+ * info will be set to found and the search data will contain the
+ * file name found. We are given our payload via walkIncludes
+ */
+void
+guessStylesheetHelper2(void *payload, void *data,
+ xmlChar * name)
+{
+ Q_UNUSED(name);
+ xmlNodePtr node = (xmlNodePtr) payload;
+ searchInfoPtr searchCriteria = (searchInfoPtr) data;
+ nodeSearchDataPtr searchData = NULL;
+ /* where did the directory/URI separator occur */
+ char *lastSlash;
+
+ if (!node || !node->doc || !searchCriteria || !searchCriteria->data ||
+ (searchCriteria->type != SEARCH_NODE))
+ return;
+
+ searchData = (nodeSearchDataPtr) searchCriteria->data;
+ if (searchData->nameInput && (searchData->absoluteNameMatch == NULL)) {
+ /* at this point we know that we have not made an absolute match
+ * but we may have made a relative match */
+ if (xmlStrCmp(node->doc->URL, searchData->nameInput) == 0) {
+ /* absolute path match great! */
+ searchData->absoluteNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) node->doc->URL);
+ searchData->node = node;
+ searchCriteria->found = 1;
+ return;
+ }
+
+
+ /* try to guess we assume that the files are unique */
+ xmlStrCpy(filesBuffer, "__#!__");
+ /* try relative to top stylesheet directory */
+ if (stylePath()) {
+ xmlStrCpy(filesBuffer, stylePath());
+ xmlStrCat(filesBuffer, searchData->nameInput);
+ }
+ if (xmlStrCmp(node->doc->URL, filesBuffer) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) filesBuffer);
+ searchData->node = node;
+ searchCriteria->found = 1;
+ return;
+ }
+
+ if (workingPath()) {
+ /* try relative to working directory */
+ xmlStrCpy(filesBuffer, workingPath());
+ xmlStrCat(filesBuffer, searchData->nameInput);
+ }
+ if (xmlStrCmp(node->doc->URL, filesBuffer) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) filesBuffer);
+ searchData->node = node;
+ searchCriteria->found = 1;
+ return;
+ }
+
+
+ /* Find the last separator of the stylsheet's URL */
+ lastSlash = xmlStrChr(node->doc->URL, URISEPARATORCHAR);
+ if (!lastSlash)
+ lastSlash = xmlStrChr(node->doc->URL, PATHCHAR);
+
+ if (lastSlash) {
+ /* Last try, assume nameInput contains only a file name
+ * Strip of the file name at end of the stylesheet doc URL */
+ lastSlash++; /* skip the slash */
+ if (xmlStrCmp(lastSlash, searchData->nameInput) == 0) {
+ /* guessed right! */
+ searchData->guessedNameMatch =
+ (xmlChar *) xmlMemStrdup((char *) node->doc->URL);
+ searchData->node = node;
+ searchCriteria->found = 1;
+ }
+ }
+ }
+}
+
+
+/**
+ * guessStylesheetName:
+ * @searchInf: Is valid
+ *
+ * Try to find a matching stylesheet name
+ * Sets the values in @searchinf depending on outcome of search
+ */
+void
+guessStylesheetName(searchInfoPtr searchCriteria)
+{
+ nodeSearchDataPtr searchData;
+
+ if (!searchCriteria)
+ return;
+
+ searchData = (nodeSearchDataPtr) searchCriteria->data;
+ if (searchData->nameInput == NULL)
+ return; /* must supply name of file to look for */
+
+ walkStylesheets((xmlHashScanner) guessStylesheetHelper,
+ searchCriteria, filesGetStylesheet());
+ if (!searchCriteria->found) {
+ /* try looking in the included stylesheets */
+ walkIncludes((xmlHashScanner) guessStylesheetHelper2,
+ searchCriteria, filesGetStylesheet());
+ }
+}
+
+
+/**
+ * stylePath:
+ *
+ * Return The base path for the top stylesheet ie
+ * ie URL minus the actual file name
+ *
+ * Returns The base path for the top stylesheet ie
+ * ie URL minus the actual file name
+ */
+xmlChar *
+stylePath(void)
+{
+ return stylePathName;
+}
+
+
+/**
+ * workingPath:
+ *
+ * Return the working directory as set by changeDir function
+ *
+ * Returns The working directory as set by changeDir function
+ */
+xmlChar *
+workingPath(void)
+{
+ return workingDirPath;
+}
+
+
+/**
+ * changeDir:
+ * @path: The path to adopt as new working directory
+ *
+ * Change working directory to path
+ *
+ * Returns 1 on success,
+ * 0 otherwise
+ */
+int
+changeDir(const xmlChar * path)
+{
+ int result = 0;
+ int charIndex;
+ const char endString[2] = { PATHCHAR, '\0' };
+ xmlChar *expandedName = NULL;
+
+
+ if (path && (xmlStrLen(path) > 0)) {
+ expandedName = filesExpandName(path);
+ } else {
+#ifdef WITH_XSLDBG_DEBUG_PROCESS
+ xsltGenericError(xsltGenericErrorContext,
+ "Error: Empty path provided to changeDir");
+#endif
+ return result;
+ }
+
+ if (!expandedName)
+ return result; /* out of memory ? */
+
+ if (xmlStrLen(expandedName) + 1 > sizeof(filesBuffer)) {
+ xsldbgGenericErrorFunc(i18n("Error: The file name \"%1\" is too long.\n").arg(xsldbgText(path)));
+ return result;
+ }
+
+ xmlStrCpy(filesBuffer, expandedName);
+ /* strip off any extra PATHCHAR's as win32's chdir function
+ * fails if we don't */
+ charIndex = xmlStrLen(filesBuffer) - 1;
+ while (charIndex && (filesBuffer[charIndex] == PATHCHAR)) {
+ charIndex--;
+ }
+ filesBuffer[charIndex + 1] = '\0';
+
+
+ if (chdir((char *) filesBuffer) == 0) {
+ if (workingDirPath)
+ xmlFree(workingDirPath);
+ /* must have path char at end of path name */
+ xmlStrCat(filesBuffer, endString);
+ workingDirPath = (xmlChar *) xmlMemStrdup((char *) filesBuffer);
+ result = 1;
+ }
+ xmlFree(expandedName); /* this will always be valid time */
+ if (!result) {
+ xsldbgGenericErrorFunc(i18n("Error: Unable to change to directory %1.\n").arg(xsldbgText(path)));
+ } else {
+ if (xslDebugStatus != DEBUG_NONE)
+ xsldbgGenericErrorFunc(i18n("Changed to directory %1.\n").arg(xsldbgText(path)));
+ }
+ return result;
+}
+
+
+/**
+ * filesLoadXmlFile:
+ * @path: xml file to load
+ * @fileType: A valid FileTypeEnum
+ *
+ * Load specified file type, freeing any memory previously used
+ *
+ * Returns 1 on success,
+ * 0 otherwise
+ */
+int
+filesLoadXmlFile(const xmlChar * path, FileTypeEnum fileType)
+{
+ int result = 0;
+
+ if (!filesFreeXmlFile(fileType))
+ return result;
+
+ switch (fileType) {
+ case FILES_XMLFILE_TYPE:
+ if (path && xmlStrLen(path)) {
+ if (optionsGetIntOption(OPTIONS_SHELL)) {
+ xsldbgGenericErrorFunc(i18n("Setting XML Data file name to %1.\n").arg(xsldbgText(path)));
+ }
+ optionsSetStringOption(OPTIONS_DATA_FILE_NAME, path);
+ }
+ topDocument = xsldbgLoadXmlData();
+ if (topDocument)
+ result = 1;
+ break;
+
+ case FILES_SOURCEFILE_TYPE:
+ if (path && xmlStrLen(path)) {
+ if (optionsGetIntOption(OPTIONS_SHELL)) {
+ xsldbgGenericErrorFunc(i18n("Setting stylesheet file name to %1.\n").arg(xsldbgText(path)));
+ }
+ optionsSetStringOption(OPTIONS_SOURCE_FILE_NAME, path);
+ }
+ topStylesheet = xsldbgLoadStylesheet();
+ if (topStylesheet && topStylesheet->doc) {
+ /* look for last slash (or baskslash) of URL */
+ char *lastSlash = xmlStrrChr(topStylesheet->doc->URL,
+ PATHCHAR);
+ const char *docUrl =
+ (const char *) topStylesheet->doc->URL;
+
+ result = 1;
+ if (docUrl && lastSlash) {
+ stylePathName = (xmlChar *) xmlMemStrdup(docUrl);
+ stylePathName[lastSlash - docUrl + 1] = '\0';
+ if (optionsGetIntOption(OPTIONS_SHELL)) {
+ xsldbgGenericErrorFunc(i18n("Setting stylesheet base path to %1.\n").arg(xsldbgText(stylePathName)));
+ }
+ } else {
+ const char cwd[4] = { '.', PATHCHAR, '\0' };
+
+ /* ie for *nix this becomes "./" */
+ stylePathName = xmlStrdup(BAD_CAST cwd);
+ }
+
+ /* try to find encoding for this stylesheet */
+ if (optionsGetIntOption(OPTIONS_AUTOENCODE))
+ filesSetEncoding((char *) topStylesheet->encoding);
+ }
+ break;
+
+ case FILES_TEMPORARYFILE_TYPE:
+ if (!path || !xmlStrLen(path)) {
+ xsldbgGenericErrorFunc(i18n("Missing file name.\n"));
+ break;
+ }
+ topDocument = xsldbgLoadXmlTemporary(path);
+ if (tempDocument)
+ result = 1;
+ break;
+ }
+ return result;
+}
+
+
+/**
+ * filesFreeXmlFile:
+ * @fileType: A valid FileTypeEnum
+ *
+ * Free memory associated with the xml file
+ *
+ * Returns 1 on success,
+ * 0 otherwise
+ */
+int
+filesFreeXmlFile(FileTypeEnum fileType)
+{
+ int result = 0, type = fileType;
+
+ switch (type) {
+ case FILES_XMLFILE_TYPE:
+ if (topDocument)
+ xmlFreeDoc(topDocument);
+ topDocument = NULL;
+ result = 1;
+ break;
+
+ case FILES_SOURCEFILE_TYPE:
+ if (topStylesheet)
+ xsltFreeStylesheet(topStylesheet);
+ if (stylePathName)
+ xmlFree(stylePathName);
+ stylePathName = NULL;
+ topStylesheet = NULL;
+ result = 1;
+ break;
+
+ case FILES_TEMPORARYFILE_TYPE:
+ if (tempDocument)
+ xmlFreeDoc(tempDocument);
+ tempDocument = NULL;
+ result = 1;
+ break;
+ }
+ return result;
+}
+
+
+/**
+ * filesGetStylesheet:
+ *
+ * Return The topmost stylesheet non-null on success,
+ * NULL otherwise
+ *
+ * Returns The topmost stylesheet non-null on success,
+ * NULL otherwise
+ */
+xsltStylesheetPtr
+filesGetStylesheet(void)
+{
+ return topStylesheet;
+}
+
+
+/**
+ * filesGetTemporaryDoc:
+ *
+ * Return The current "temporary" document
+ *
+ * Returns The current "temporary" document
+ */
+xmlDocPtr
+filesGetTemporaryDoc(void)
+{
+ return tempDocument;
+}
+
+
+/**
+ * filesGetMainDoc:
+ *
+ * Return The main docment
+ *
+ * Returns The main docment
+ */
+xmlDocPtr
+filesGetMainDoc(void)
+{
+ return topDocument;
+}
+
+
+/**
+ * filesReloaded:
+ * @reloaded: if = -1 then ignore @reloaded
+ * otherwise change the status of files to value of @reloaded
+ *
+ * Returns 1 if stylesheet or its xml data file has been "flaged" as reloaded,
+ * 0 otherwise
+ */
+int
+filesReloaded(int reloaded)
+{
+ static int changed = 0;
+
+ if (reloaded >= 0) {
+ changed = reloaded;
+ }
+
+ return changed;
+}
+
+
+
+/**
+ * filesInit:
+ *
+ * Initialize the file related structures
+ * Returns 1 on success,
+ * 0 otherwise
+ */
+int
+filesInit(void)
+{
+ int result = 0;
+
+ terminalIO = NULL;
+#ifdef __riscos
+ ttyName = ":tt"; /* Default tty */
+#endif
+#ifdef HAVE_UNISTD
+ ttyName = ttyname(fileno(stdin));
+ /* save out io for when/if we send debugging to a terminal */
+ oldStdin = stdin;
+ oldStdout = stdout;
+ oldStderr = stderr;
+#endif
+ topDocument = NULL;
+ tempDocument = NULL;
+ topStylesheet = NULL;
+ entityNameList = arrayListNew(4, (freeItemFunc) filesFreeEntityInfo);
+#if defined(HAVE_INCLUDE_FIX) && (LIBXML_VERSION < 20508)
+ xmlSetEntityReferenceFunc(filesEntityRef);
+#endif
+
+ /* setup the encoding */
+ encodeInBuff = xmlBufferCreate();
+ encodeOutBuff = xmlBufferCreate();
+
+ /* check the result so far and lastly perform platform specific
+ * initialization */
+ if (entityNameList && encodeInBuff && encodeOutBuff &&
+ filesPlatformInit())
+ result = 1;
+ return result;
+}
+
+/**
+ * filesFree:
+ *
+ * Free memory used by file related structures
+ */
+void
+filesFree(void)
+{
+ int result;
+
+ if (terminalIO) {
+ fclose(terminalIO);
+ terminalIO = NULL;
+ }
+ if (termName) {
+ xmlFree(termName);
+ termName = NULL;
+ }
+
+ result = filesFreeXmlFile(FILES_SOURCEFILE_TYPE);
+ if (result)
+ result = filesFreeXmlFile(FILES_XMLFILE_TYPE);
+ if (result)
+ result = filesFreeXmlFile(FILES_TEMPORARYFILE_TYPE);
+ if (!result){
+#ifdef WITH_XSLDBG_DEBUG_PROCESS
+ xsltGenericError(xsltGenericErrorContext,
+ "Error: Unable to free memory used by XML/XSLT files\n");
+#endif
+ }
+ if (stylePathName) {
+ xmlFree(stylePathName);
+ stylePathName = NULL;
+ }
+
+ if (workingDirPath) {
+ xmlFree(workingDirPath);
+ workingDirPath = NULL;
+ }
+
+ if (entityNameList) {
+ arrayListFree(entityNameList);
+ entityNameList = NULL;
+ }
+
+ /* Free memory used by encoding related structures */
+ if (encodeInBuff)
+ xmlBufferFree(encodeInBuff);
+
+ if (encodeOutBuff)
+ xmlBufferFree(encodeOutBuff);
+
+ /* close current encoding */
+ filesSetEncoding(NULL);
+
+ if (currentUrl)
+ xmlFree(currentUrl);
+
+ /* free any memory used by platform specific files module */
+ filesPlatformFree();
+}
+
+
+/**
+ * filesIsSourceFile:
+ * @fileName : is valid
+ *
+ * Returns true if @name has the ".xsl" externsion
+ */
+int
+filesIsSourceFile(xmlChar * fileName)
+{
+ return strstr((char *) fileName, ".xsl") ||
+ strstr((char *) fileName, ".Xsl") ||
+ strstr((char *) fileName, ".XSL");
+}
+
+
+
+entityInfoPtr
+filesNewEntityInfo(const xmlChar * SystemID, const xmlChar * PublicID)
+{
+
+ entityInfoPtr result = (entityInfoPtr) xmlMalloc(sizeof(entityInfo));
+
+ if (result) {
+ if (SystemID)
+ result->SystemID = xmlStrdup(SystemID);
+ else
+ result->SystemID = xmlStrdup(BAD_CAST "");
+
+ if (PublicID)
+ result->PublicID = xmlStrdup(PublicID);
+ else
+ result->PublicID = xmlStrdup(BAD_CAST "");
+ }
+ return result;
+}
+
+void
+filesFreeEntityInfo(entityInfoPtr info)
+{
+ if (!info)
+ return;
+
+ if (info->SystemID)
+ xmlFree(info->SystemID);
+
+ if (info->PublicID)
+ xmlFree(info->PublicID);
+ xmlFree(info);
+}
+
+/**
+ * filesAddEntityName:
+ * @name : is valid
+ *
+ * Add name to entity name list of know external entities if
+ * it does not already exist in list
+ */
+void
+
+filesAddEntityName(const xmlChar * SystemID, const xmlChar * PublicID)
+{
+ int entityIndex = 0;
+ entityInfoPtr tempItem;
+
+ if (!SystemID || !filesEntityList())
+ return;
+
+ for (entityIndex = 0;
+ entityIndex < arrayListCount(filesEntityList()); entityIndex++) {
+ tempItem =
+ (entityInfoPtr) arrayListGet(filesEntityList(), entityIndex);
+ if (tempItem && xmlStrEqual(SystemID, tempItem->SystemID)) {
+ /* name aready exits so don't add it */
+ return;
+ }
+
+ }
+
+ tempItem = filesNewEntityInfo(SystemID, PublicID);
+ arrayListAdd(filesEntityList(), tempItem);
+}
+
+
+/**
+ * filesEntityRef :
+ * @ent : Is valid as provided by libxslt
+ * @firstNode : Is valid
+ * @lastNode : Is Valid
+ *
+ * Fixes the nodes from firstNode to lastNode so that debugging can occur
+ */
+void
+
+filesEntityRef(xmlEntityPtr ent, xmlNodePtr firstNode, xmlNodePtr lastNode)
+{
+ xmlNodePtr node = firstNode;
+ if (!firstNode || !ent || !ent->SystemID ||
+ (ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) )
+ return;
+
+ if (ent->ExternalID)
+ filesAddEntityName(ent->SystemID, ent->ExternalID);
+ else
+ filesAddEntityName(ent->URI, BAD_CAST "");
+ while (node){
+ filesSetBaseUri(node, ent->URI);
+ if (node != lastNode)
+ node = node->next;
+ else
+ node = NULL;
+ }
+}
+
+
+
+ /**
+ * filesSetBaseUri:
+ * @node : Is valid and has a doc parent
+ * @uri : Is Valid
+ *
+ * Set the base uri for this node. Function is used when xml file
+ * has external entities in its DTD
+ *
+ * Returns 1 if successful,
+ * 0 otherwise
+ */
+
+int
+filesSetBaseUri(xmlNodePtr node, const xmlChar * uri)
+{
+ int result = 0;
+
+ if (!node || !uri)
+ return result;
+ else {
+ if (node->type == XML_ELEMENT_NODE){
+ xmlChar *xsldbgUrlCopy = xmlGetProp(node, BAD_CAST "xsldbg:uri");
+ if (!xsldbgUrlCopy)
+ xmlNewProp(node, BAD_CAST "xsldbg:uri", uri);
+ else
+ xmlFree(xsldbgUrlCopy);
+ }
+ result = 1;
+ }
+ return result;
+}
+
+
+ /**
+ * filesGetBaseUri:
+ * @node : Is valid and has a doc parent
+ *
+ * Get a copy of the base uri for this node. Function is most usefull
+ * used when xml file has external entities in its DTD
+ *
+ * Returns the a copy of the base uri for this node,
+ * NULL otherwise
+ */
+xmlChar *
+filesGetBaseUri(xmlNodePtr node)
+{
+ xmlChar *result = NULL;
+
+ if (!node || !node->doc)
+ return result;
+
+ while (node && node->parent) {
+ /*
+ * result = xmlGetNsProp(node, BAD_CAST "uri", XSLDBG_XML_NAMESPACE);
+ */
+ if (node->type == XML_ELEMENT_NODE) {
+ result = xmlGetProp(node, BAD_CAST "xsldbg:uri");
+ if (result)
+ break;
+ }
+ node = node->parent;
+ }
+
+ if (!result && node->doc && node->doc->URL)
+ result = xmlStrdup(node->doc->URL);
+
+ return result;
+}
+
+
+
+
+/**
+ * filesEntityList:
+ *
+ * Return the list entity names used for documents loaded
+ *
+ * Returns the list entity names used for documents loaded
+ */
+arrayListPtr
+filesEntityList(void)
+{
+ return entityNameList;
+}
+
+extern int intVolitileOptions[OPTIONS_LAST_INT_OPTIONID - OPTIONS_FIRST_INT_OPTIONID + 1];
+
+/**
+ * filesLoadCatalogs:
+ *
+ * Load the catalogs specifed by OPTIONS_CATALOG_NAMES if
+ * OPTIONS_CATALOGS is enabled
+ * Returns 1 if sucessful
+ * 0 otherwise
+ */
+int
+filesLoadCatalogs(void)
+{
+ int result = 0;
+ const char *catalogs = NULL;
+
+ xmlCatalogCleanup();
+ if (optionsGetIntOption(OPTIONS_CATALOGS)) {
+ if (optionsGetStringOption(OPTIONS_CATALOG_NAMES) == NULL) {
+ /* use the SGML catalog */
+#ifdef __riscos
+ catalogs = getenv("SGML$CatalogFiles");
+#else
+ catalogs = getenv("SGML_CATALOG_FILES");
+#endif
+ if (catalogs == NULL) {
+#ifdef __riscos
+ xsldbgGenericErrorFunc("Warning: Environment variable SGML$CatalogFiles is not set.\n");
+#else
+ xsldbgGenericErrorFunc("Warning: Environment variabe SGML_CATALOG_FILES FILES not set.\n");
+#endif
+ } else
+ /* copy the current catalog name(s) for user to see */
+ optionsSetStringOption(OPTIONS_CATALOG_NAMES,
+ (xmlChar *) catalogs);
+ } else
+ /* Use the current catalog settings from users*/
+ catalogs = (char *)
+ optionsGetStringOption(OPTIONS_CATALOG_NAMES);
+
+ result = 1;
+ }
+
+ if (catalogs){
+ /* Load the new cataog selection */
+ xmlLoadCatalogs(catalogs);
+ }else{
+ /* Use default catalogs */
+ xmlInitializeCatalog();
+ }
+ return result;
+}
+
+
+
+
+ /**
+ * filesEncode:
+ * @text: Is valid, text to translate from UTF-8,
+ *
+ * Return A new string of converted @text
+ *
+ * Returns A new string of converted @text, may be NULL
+ */
+xmlChar *
+filesEncode(const xmlChar * text)
+{
+ xmlChar *result = NULL;
+
+ if (!text)
+ return result;
+
+ if (!stdoutEncoding || !encodeInBuff || !encodeOutBuff)
+ return xmlStrdup(text); /* no encoding active return as UTF-8 */
+
+ xmlBufferEmpty(encodeInBuff);
+ xmlBufferEmpty(encodeOutBuff);
+ xmlBufferCat(encodeInBuff, text);
+
+ if (xmlCharEncOutFunc(stdoutEncoding, encodeOutBuff, encodeInBuff)
+ >= 0) {
+ result = xmlStrdup(xmlBufferContent(encodeOutBuff));
+ } else {
+ xsldbgGenericErrorFunc(i18n("Encoding of text failed.\n"));
+ return xmlStrdup(text); /* panic, return as UTF-8 */
+ }
+ return result;
+}
+
+
+
+ /**
+ * filesDeccode:
+ * @text: Is valid, text to translate from current encoding to UTF-8,
+ *
+ * Return A string of converted @text
+ *
+ * Returns A string of converted @text, may be NULL
+ */
+xmlChar *
+filesDecode(const xmlChar * text)
+{
+ xmlChar *result = NULL;
+
+ if (!text)
+ return result;
+
+ if (!stdoutEncoding || !encodeInBuff || !encodeOutBuff)
+ return xmlStrdup(text); /* no encoding active return as UTF-8 */
+
+ xmlBufferEmpty(encodeInBuff);
+ xmlBufferEmpty(encodeOutBuff);
+ xmlBufferCat(encodeInBuff, text);
+
+ if (xmlCharEncInFunc(stdoutEncoding, encodeOutBuff, encodeInBuff)
+ >= 0) {
+ result = xmlStrdup(xmlBufferContent(encodeOutBuff));
+ } else {
+ xsldbgGenericErrorFunc(i18n("Encoding of text failed.\n"));
+ return xmlStrdup(text); /* panic, return @text unchanged */
+ }
+ return result;
+}
+
+
+ /*
+ * filesSetEncoding:
+ * @encoding : Is a valid encoding supported by the iconv library or NULL
+ *
+ * Opens encoding for all standard output to @encoding. If @encoding
+ * is NULL then close current encoding and use UTF-8 as output encoding
+ *
+ * Returns 1 if successful in setting the encoding of all standard output
+ * to @encoding
+ * 0 otherwise
+ */
+int
+filesSetEncoding(const char *encoding)
+{
+ int result = 0;
+
+ if (encoding) {
+ /* don't switch encoding unless we've found a valid encoding */
+ xmlCharEncodingHandlerPtr tempEncoding =
+ xmlFindCharEncodingHandler(encoding);
+ if (tempEncoding) {
+ filesSetEncoding(NULL); /* re-use code to close encoding */
+ stdoutEncoding = tempEncoding;
+ result =
+ (xmlCharEncOutFunc(stdoutEncoding, encodeOutBuff, NULL)
+ >= 0);
+ if (!result) {
+ xmlCharEncCloseFunc(stdoutEncoding);
+ stdoutEncoding = NULL;
+ xsldbgGenericErrorFunc(i18n("Unable to initialize encoding %1.").arg(xsldbgText(encoding)));
+ } else
+ optionsSetStringOption(OPTIONS_ENCODING,
+ (xmlChar *) encoding);
+ } else {
+ xsldbgGenericErrorFunc(i18n("Invalid encoding %1.\n").arg(xsldbgText(encoding)));
+ }
+ } else {
+ /* close encoding and use UTF-8 */
+ if (stdoutEncoding)
+ result = (xmlCharEncCloseFunc(stdoutEncoding) >= 0);
+ else
+ result = 1;
+ stdoutEncoding = NULL;
+ }
+ return result;
+}
+
+
+
+ /**
+ * filesMoreFile:
+ * @fileName : May be NULL
+ * @file : May be NULL
+ *
+ * Do a "more" like print of file specified by @fileName OR
+ * @file. If both are provided @file will be used. The content
+ * of file chosen must be in UTF-8, and will be printed in
+ * the current encoding selected.The function will pause output
+ * after FILES_NO_LINES lines have been printed waiting for
+ * user to enter "q" to quit or any other text to continue.
+ *
+ * Returns 1 if successful,
+ * 0 otherwise
+ */
+int
+filesMoreFile(const xmlChar * fileName, FILE * file)
+{
+ int result = 0;
+ int openedFile = 0;
+ int lineCount;
+ int reachedEof = 0;
+
+ if (fileName && !file) {
+#ifdef __riscos
+ /* convert into RISC OS format a *nix style file name */
+ fileName = (const xmlChar *) riscosfilename((char *) fileName);
+#endif
+ file = fopen((char *) fileName, "r");
+ openedFile = 1; /* since we opened the file we must close it */
+ }
+ if (file) {
+ while (!feof(file) && !reachedEof) {
+ lineCount = 0;
+ while (!feof(file) && (lineCount < FILES_NO_LINES) &&
+ !reachedEof) {
+ if (fgets((char *) filesBuffer, sizeof(filesBuffer), file)) {
+ xsltGenericError(xsltGenericErrorContext, "%s",
+ filesBuffer);
+ lineCount++;
+ } else {
+ reachedEof = 1;
+ }
+ }
+
+ if (!feof(file) && !reachedEof) {
+ xsldbgGenericErrorFunc(i18n(" ----- more ---- \n"));
+ fflush(stderr);
+ if (fgets((char *) filesBuffer, sizeof(filesBuffer), stdin)) {
+ if ((*filesBuffer == 'q') || (*filesBuffer == 'Q'))
+ reachedEof = 1;
+ } else {
+ reachedEof = 1;
+ }
+ }
+ }
+
+ if (openedFile) {
+ fclose(file);
+ }
+ xsltGenericError(xsltGenericErrorContext, "\n");
+ result = 1;
+ } else {
+#ifdef WITH_XSLDBG_DEBUG_PROCESS
+ xsltGenericError(xsltGenericErrorContext,
+ "Error: No valid file provided to print\n");
+#endif
+ }
+
+
+ return result;
+}
+
+
+ /**
+ * filesSearchResultsPath:
+ *
+ * Get the base path to be used for storing search results
+ *
+ * Returns The base path to be used for storing search results
+ */
+const xmlChar *
+filesSearchResultsPath()
+{
+ const xmlChar *result;
+
+ if (optionsGetStringOption(OPTIONS_SEARCH_RESULTS_PATH))
+ result = optionsGetStringOption(OPTIONS_SEARCH_RESULTS_PATH);
+ else
+ result = stylePath();
+
+ return result;
+}
+
+
+ /**
+ * filesURItoFileName:
+ * @uri : A valid URI that uses the "file://" prefix
+ *
+ * Return A copy of the conversion of @uri to a file name
+ * that is suitable to be used with the fopen function.
+ * May be NULL, if out of memory, @uri does not use the
+ * "file://" prefix, or unable to convert to a valid file name
+ *
+ * Returns A copy of the conversion of @uri to a file name
+ * that is suitable to be used with the fopen function.
+ * May be NULL, if out of memory, @uri does not use the
+ * "file://" prefix, or unable to convert to a valid file name
+ *
+ */
+xmlChar *filesURItoFileName(const xmlChar* uri)
+{
+ xmlChar *result = NULL;
+ xmlChar *unescapedFileName = NULL;
+ const xmlChar* tempName = NULL;
+
+ if (uri){
+ if (!xmlStrnCmp(uri, "file://localhost", 16 )){
+ tempName = uri + 16;
+ }else{
+#if defined(WIN32) && ! defined(CYGWIN)
+ if (!xmlStrnCmp(uri, "file:///", 8))
+ tempName = uri + 8;
+#else
+ if (!xmlStrnCmp(uri, "file:/", 6))
+ tempName = uri + 5; // we need the leading '/'*/
+ while (tempName[0] == '/' && tempName[1] == '/' )
+ tempName++;
+#endif
+ }
+
+ /* If we've found something check to see if the file name
+ found is to be valid */
+ if (tempName)
+ result = (xmlChar*) xmlStrdup(tempName);
+ unescapedFileName = (xmlChar*) xmlStrdup(tempName);
+ if (result && unescapedFileName){
+ if (PATHCHAR != URISEPARATORCHAR){
+ /* Must convert path separators first */
+ xmlChar *probe = result;
+ while(*probe != '\0'){
+ if (*probe == (xmlChar)URISEPARATORCHAR)
+ *probe = (xmlChar)PATHCHAR;
+ probe++;
+ }
+ }
+ /* Now unescape the file name in result so far
+ * NB: An unescaped name takes less memory that an escaped name
+ */
+ xmlURIUnescapeString((char*)result, -1, (char*)unescapedFileName);
+ xmlFree(result);
+ /* success we've got an local unescaped file name */
+ result = unescapedFileName;
+ }else{
+ xsldbgGenericErrorFunc(i18n("Error: Out of memory.\n"));
+ if (result){
+ xmlFree(result);
+ }
+ if (unescapedFileName) /* not needed, here for completeness */
+ xmlFree(unescapedFileName);
+
+ result = NULL;
+ }
+ }else{
+ xsldbgGenericErrorFunc(i18n("Error: Unable to convert %1 to local file name.\n").arg(xsldbgText(uri)));
+ }
+
+
+ return result;
+}
+
+
+/* TODO in xsldbg 3.x rename these to use files prefix */
+
+/**
+ * xsldbgUpdateFileDetails:
+ * @node : A valid node
+ *
+ * Update the URL and line number that we stoped at
+ */
+void
+xsldbgUpdateFileDetails(xmlNodePtr node)
+{
+ if ((node != NULL) && (node->doc != NULL)){
+ if (currentUrl != NULL)
+ xmlFree(currentUrl);
+ currentUrl = filesGetBaseUri(node);
+ currentLineNo = xmlGetLineNo(node);
+ }
+}
+
+
+/**
+ * xsldbgLineNo:
+ *
+ * What line number are we at
+ *
+ * Returns The current line number of xsldbg, may be -1
+ **/
+int
+xsldbgLineNo(void)
+{
+ return currentLineNo;
+}
+
+
+/**
+ * xsldbgUrl:
+ *
+ * What URL did we stop at
+ *
+ * Returns A NEW copy of URL stopped at. Caller must free memory for URL.
+ * May be NULL
+ */
+xmlChar *
+xsldbgUrl(void)
+{
+ if (currentUrl != NULL)
+ return (xmlChar *) xmlMemStrdup((char *) currentUrl);
+ else
+ return NULL;
+}