You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdewebdev/kxsldbg/kxsldbgpart/libxsldbg/files.cpp

1421 lines
38 KiB

/***************************************************************************
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>
#else
#include <unistd.h>
#endif
#endif /* BUILD_DOCS */
#include <cstdlib>
/* 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);
/* 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;
}