/*************************************************************************** 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 #include #include #include #include #include /* needed by filesTranslate, filesEncoding functions */ #include /* needed for xmlURIUnescapeString */ #include "debugXSL.h" #include "files.h" #include "utils.h" #include "options.h" #include "xsldbgthread.h" #ifdef WIN32 #include #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; }