File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / HTMLtree.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:20 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

    1: /*
    2:  * HTMLtree.c : implementation of access function for an HTML tree.
    3:  *
    4:  * See Copyright for the status of this software.
    5:  *
    6:  * daniel@veillard.com
    7:  */
    8: 
    9: 
   10: #define IN_LIBXML
   11: #include "libxml.h"
   12: #ifdef LIBXML_HTML_ENABLED
   13: 
   14: #include <string.h> /* for memset() only ! */
   15: 
   16: #ifdef HAVE_CTYPE_H
   17: #include <ctype.h>
   18: #endif
   19: #ifdef HAVE_STDLIB_H
   20: #include <stdlib.h>
   21: #endif
   22: 
   23: #include <libxml/xmlmemory.h>
   24: #include <libxml/HTMLparser.h>
   25: #include <libxml/HTMLtree.h>
   26: #include <libxml/entities.h>
   27: #include <libxml/valid.h>
   28: #include <libxml/xmlerror.h>
   29: #include <libxml/parserInternals.h>
   30: #include <libxml/globals.h>
   31: #include <libxml/uri.h>
   32: 
   33: /************************************************************************
   34:  *									*
   35:  *   		Getting/Setting encoding meta tags			*
   36:  *									*
   37:  ************************************************************************/
   38: 
   39: /**
   40:  * htmlGetMetaEncoding:
   41:  * @doc:  the document
   42:  * 
   43:  * Encoding definition lookup in the Meta tags
   44:  *
   45:  * Returns the current encoding as flagged in the HTML source
   46:  */
   47: const xmlChar *
   48: htmlGetMetaEncoding(htmlDocPtr doc) {
   49:     htmlNodePtr cur;
   50:     const xmlChar *content;
   51:     const xmlChar *encoding;
   52: 
   53:     if (doc == NULL)
   54: 	return(NULL);
   55:     cur = doc->children;
   56: 
   57:     /*
   58:      * Search the html
   59:      */
   60:     while (cur != NULL) {
   61: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
   62: 	    if (xmlStrEqual(cur->name, BAD_CAST"html"))
   63: 		break;
   64: 	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
   65: 		goto found_head;
   66: 	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
   67: 		goto found_meta;
   68: 	}
   69: 	cur = cur->next;
   70:     }
   71:     if (cur == NULL)
   72: 	return(NULL);
   73:     cur = cur->children;
   74: 
   75:     /*
   76:      * Search the head
   77:      */
   78:     while (cur != NULL) {
   79: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
   80: 	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
   81: 		break;
   82: 	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
   83: 		goto found_meta;
   84: 	}
   85: 	cur = cur->next;
   86:     }
   87:     if (cur == NULL)
   88: 	return(NULL);
   89: found_head:
   90:     cur = cur->children;
   91: 
   92:     /*
   93:      * Search the meta elements
   94:      */
   95: found_meta:
   96:     while (cur != NULL) {
   97: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
   98: 	    if (xmlStrEqual(cur->name, BAD_CAST"meta")) {
   99: 		xmlAttrPtr attr = cur->properties;
  100: 		int http;
  101: 		const xmlChar *value;
  102: 
  103: 		content = NULL;
  104: 		http = 0;
  105: 		while (attr != NULL) {
  106: 		    if ((attr->children != NULL) &&
  107: 		        (attr->children->type == XML_TEXT_NODE) &&
  108: 		        (attr->children->next == NULL)) {
  109: 			value = attr->children->content;
  110: 			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
  111: 			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
  112: 			    http = 1;
  113: 			else if ((value != NULL)
  114: 			 && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
  115: 			    content = value;
  116: 			if ((http != 0) && (content != NULL))
  117: 			    goto found_content;
  118: 		    }
  119: 		    attr = attr->next;
  120: 		}
  121: 	    }
  122: 	}
  123: 	cur = cur->next;
  124:     }
  125:     return(NULL);
  126: 
  127: found_content:
  128:     encoding = xmlStrstr(content, BAD_CAST"charset=");
  129:     if (encoding == NULL) 
  130: 	encoding = xmlStrstr(content, BAD_CAST"Charset=");
  131:     if (encoding == NULL) 
  132: 	encoding = xmlStrstr(content, BAD_CAST"CHARSET=");
  133:     if (encoding != NULL) {
  134: 	encoding += 8;
  135:     } else {
  136: 	encoding = xmlStrstr(content, BAD_CAST"charset =");
  137: 	if (encoding == NULL) 
  138: 	    encoding = xmlStrstr(content, BAD_CAST"Charset =");
  139: 	if (encoding == NULL) 
  140: 	    encoding = xmlStrstr(content, BAD_CAST"CHARSET =");
  141: 	if (encoding != NULL)
  142: 	    encoding += 9;
  143:     }
  144:     if (encoding != NULL) {
  145: 	while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
  146:     }
  147:     return(encoding);
  148: }
  149: 
  150: /**
  151:  * htmlSetMetaEncoding:
  152:  * @doc:  the document
  153:  * @encoding:  the encoding string
  154:  *
  155:  * Sets the current encoding in the Meta tags
  156:  * NOTE: this will not change the document content encoding, just
  157:  * the META flag associated.
  158:  *
  159:  * Returns 0 in case of success and -1 in case of error
  160:  */
  161: int
  162: htmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) {
  163:     htmlNodePtr cur, meta = NULL, head = NULL;
  164:     const xmlChar *content = NULL;
  165:     char newcontent[100];
  166: 
  167:     newcontent[0] = 0;
  168: 
  169:     if (doc == NULL)
  170: 	return(-1);
  171: 
  172:     /* html isn't a real encoding it's just libxml2 way to get entities */
  173:     if (!xmlStrcasecmp(encoding, BAD_CAST "html"))
  174:         return(-1);
  175: 
  176:     if (encoding != NULL) {
  177: 	snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s",
  178:                 (char *)encoding);
  179: 	newcontent[sizeof(newcontent) - 1] = 0;
  180:     }
  181: 
  182:     cur = doc->children;
  183: 
  184:     /*
  185:      * Search the html
  186:      */
  187:     while (cur != NULL) {
  188: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
  189: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"html") == 0)
  190: 		break;
  191: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
  192: 		goto found_head;
  193: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0)
  194: 		goto found_meta;
  195: 	}
  196: 	cur = cur->next;
  197:     }
  198:     if (cur == NULL)
  199: 	return(-1);
  200:     cur = cur->children;
  201: 
  202:     /*
  203:      * Search the head
  204:      */
  205:     while (cur != NULL) {
  206: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
  207: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
  208: 		break;
  209: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {
  210:                 head = cur->parent;
  211: 		goto found_meta;
  212:             }
  213: 	}
  214: 	cur = cur->next;
  215:     }
  216:     if (cur == NULL)
  217: 	return(-1);
  218: found_head:
  219:     head = cur;
  220:     if (cur->children == NULL)
  221:         goto create;
  222:     cur = cur->children;
  223: 
  224: found_meta:
  225:     /*
  226:      * Search and update all the remaining the meta elements carrying
  227:      * encoding informations
  228:      */
  229:     while (cur != NULL) {
  230: 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
  231: 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {
  232: 		xmlAttrPtr attr = cur->properties;
  233: 		int http;
  234: 		const xmlChar *value;
  235: 
  236: 		content = NULL;
  237: 		http = 0;
  238: 		while (attr != NULL) {
  239: 		    if ((attr->children != NULL) &&
  240: 		        (attr->children->type == XML_TEXT_NODE) &&
  241: 		        (attr->children->next == NULL)) {
  242: 			value = attr->children->content;
  243: 			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
  244: 			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
  245: 			    http = 1;
  246: 			else
  247:                         {
  248:                            if ((value != NULL) &&
  249:                                (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
  250: 			       content = value;
  251:                         }
  252: 		        if ((http != 0) && (content != NULL))
  253: 			    break;
  254: 		    }
  255: 		    attr = attr->next;
  256: 		}
  257: 		if ((http != 0) && (content != NULL)) {
  258: 		    meta = cur;
  259: 		    break;
  260: 		}
  261: 
  262: 	    }
  263: 	}
  264: 	cur = cur->next;
  265:     }
  266: create:
  267:     if (meta == NULL) {
  268:         if ((encoding != NULL) && (head != NULL)) {
  269:             /*
  270:              * Create a new Meta element with the right attributes
  271:              */
  272: 
  273:             meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
  274:             if (head->children == NULL)
  275:                 xmlAddChild(head, meta);
  276:             else
  277:                 xmlAddPrevSibling(head->children, meta);
  278:             xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
  279:             xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
  280:         }
  281:     } else {
  282:         /* remove the meta tag if NULL is passed */
  283:         if (encoding == NULL) {
  284:             xmlUnlinkNode(meta);
  285:             xmlFreeNode(meta);
  286:         }
  287:         /* change the document only if there is a real encoding change */
  288:         else if (xmlStrcasestr(content, encoding) == NULL) {
  289:             xmlSetProp(meta, BAD_CAST"content", BAD_CAST newcontent);
  290:         }
  291:     }
  292: 
  293: 
  294:     return(0);
  295: }
  296: 
  297: /**
  298:  * booleanHTMLAttrs:
  299:  *
  300:  * These are the HTML attributes which will be output
  301:  * in minimized form, i.e. <option selected="selected"> will be
  302:  * output as <option selected>, as per XSLT 1.0 16.2 "HTML Output Method"
  303:  *
  304:  */
  305: static const char* htmlBooleanAttrs[] = {
  306:   "checked", "compact", "declare", "defer", "disabled", "ismap",
  307:   "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly",
  308:   "selected", NULL
  309: };
  310: 
  311: 
  312: /**
  313:  * htmlIsBooleanAttr:
  314:  * @name:  the name of the attribute to check
  315:  *
  316:  * Determine if a given attribute is a boolean attribute.
  317:  * 
  318:  * returns: false if the attribute is not boolean, true otherwise.
  319:  */
  320: int
  321: htmlIsBooleanAttr(const xmlChar *name)
  322: {
  323:     int i = 0;
  324: 
  325:     while (htmlBooleanAttrs[i] != NULL) {
  326:         if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0)
  327:             return 1;
  328:         i++;
  329:     }
  330:     return 0;
  331: }
  332: 
  333: #ifdef LIBXML_OUTPUT_ENABLED
  334: /*
  335:  * private routine exported from xmlIO.c
  336:  */
  337: xmlOutputBufferPtr
  338: xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
  339: /************************************************************************
  340:  *									*
  341:  * 			Output error handlers				*
  342:  *									*
  343:  ************************************************************************/
  344: /**
  345:  * htmlSaveErrMemory:
  346:  * @extra:  extra informations
  347:  *
  348:  * Handle an out of memory condition
  349:  */
  350: static void
  351: htmlSaveErrMemory(const char *extra)
  352: {
  353:     __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
  354: }
  355: 
  356: /**
  357:  * htmlSaveErr:
  358:  * @code:  the error number
  359:  * @node:  the location of the error.
  360:  * @extra:  extra informations
  361:  *
  362:  * Handle an out of memory condition
  363:  */
  364: static void
  365: htmlSaveErr(int code, xmlNodePtr node, const char *extra)
  366: {
  367:     const char *msg = NULL;
  368: 
  369:     switch(code) {
  370:         case XML_SAVE_NOT_UTF8:
  371: 	    msg = "string is not in UTF-8\n";
  372: 	    break;
  373: 	case XML_SAVE_CHAR_INVALID:
  374: 	    msg = "invalid character value\n";
  375: 	    break;
  376: 	case XML_SAVE_UNKNOWN_ENCODING:
  377: 	    msg = "unknown encoding %s\n";
  378: 	    break;
  379: 	case XML_SAVE_NO_DOCTYPE:
  380: 	    msg = "HTML has no DOCTYPE\n";
  381: 	    break;
  382: 	default:
  383: 	    msg = "unexpected error number\n";
  384:     }
  385:     __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
  386: }
  387: 
  388: /************************************************************************
  389:  *									*
  390:  *   		Dumping HTML tree content to a simple buffer		*
  391:  *									*
  392:  ************************************************************************/
  393: 
  394: static int
  395: htmlNodeDumpFormat(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
  396: 	           int format);
  397: 
  398: /**
  399:  * htmlNodeDumpFormat:
  400:  * @buf:  the HTML buffer output
  401:  * @doc:  the document
  402:  * @cur:  the current node
  403:  * @format:  should formatting spaces been added
  404:  *
  405:  * Dump an HTML node, recursive behaviour,children are printed too.
  406:  *
  407:  * Returns the number of byte written or -1 in case of error
  408:  */
  409: static int
  410: htmlNodeDumpFormat(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
  411: 	           int format) {
  412:     unsigned int use;
  413:     int ret;
  414:     xmlOutputBufferPtr outbuf;
  415: 
  416:     if (cur == NULL) {
  417: 	return (-1);
  418:     }
  419:     if (buf == NULL) {
  420: 	return (-1);
  421:     }
  422:     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
  423:     if (outbuf == NULL) {
  424:         htmlSaveErrMemory("allocating HTML output buffer");
  425: 	return (-1);
  426:     }
  427:     memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
  428:     outbuf->buffer = buf;
  429:     outbuf->encoder = NULL;
  430:     outbuf->writecallback = NULL;
  431:     outbuf->closecallback = NULL;
  432:     outbuf->context = NULL;
  433:     outbuf->written = 0;
  434: 
  435:     use = buf->use;
  436:     htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
  437:     xmlFree(outbuf);
  438:     ret = buf->use - use;
  439:     return (ret);
  440: }
  441: 
  442: /**
  443:  * htmlNodeDump:
  444:  * @buf:  the HTML buffer output
  445:  * @doc:  the document
  446:  * @cur:  the current node
  447:  *
  448:  * Dump an HTML node, recursive behaviour,children are printed too,
  449:  * and formatting returns are added.
  450:  *
  451:  * Returns the number of byte written or -1 in case of error
  452:  */
  453: int
  454: htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
  455:     xmlInitParser();
  456: 
  457:     return(htmlNodeDumpFormat(buf, doc, cur, 1));
  458: }
  459: 
  460: /**
  461:  * htmlNodeDumpFileFormat:
  462:  * @out:  the FILE pointer
  463:  * @doc:  the document
  464:  * @cur:  the current node
  465:  * @encoding: the document encoding
  466:  * @format:  should formatting spaces been added
  467:  *
  468:  * Dump an HTML node, recursive behaviour,children are printed too.
  469:  *
  470:  * TODO: if encoding == NULL try to save in the doc encoding
  471:  *
  472:  * returns: the number of byte written or -1 in case of failure.
  473:  */
  474: int
  475: htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc,
  476: 	               xmlNodePtr cur, const char *encoding, int format) {
  477:     xmlOutputBufferPtr buf;
  478:     xmlCharEncodingHandlerPtr handler = NULL;
  479:     int ret;
  480: 
  481:     xmlInitParser();
  482: 
  483:     if (encoding != NULL) {
  484: 	xmlCharEncoding enc;
  485: 
  486: 	enc = xmlParseCharEncoding(encoding);
  487: 	if (enc != XML_CHAR_ENCODING_UTF8) {
  488: 	    handler = xmlFindCharEncodingHandler(encoding);
  489: 	    if (handler == NULL)
  490: 		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
  491: 	}
  492:     }
  493: 
  494:     /*
  495:      * Fallback to HTML or ASCII when the encoding is unspecified
  496:      */
  497:     if (handler == NULL)
  498: 	handler = xmlFindCharEncodingHandler("HTML");
  499:     if (handler == NULL)
  500: 	handler = xmlFindCharEncodingHandler("ascii");
  501: 
  502:     /* 
  503:      * save the content to a temp buffer.
  504:      */
  505:     buf = xmlOutputBufferCreateFile(out, handler);
  506:     if (buf == NULL) return(0);
  507: 
  508:     htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
  509: 
  510:     ret = xmlOutputBufferClose(buf);
  511:     return(ret);
  512: }
  513: 
  514: /**
  515:  * htmlNodeDumpFile:
  516:  * @out:  the FILE pointer
  517:  * @doc:  the document
  518:  * @cur:  the current node
  519:  *
  520:  * Dump an HTML node, recursive behaviour,children are printed too,
  521:  * and formatting returns are added.
  522:  */
  523: void
  524: htmlNodeDumpFile(FILE *out, xmlDocPtr doc, xmlNodePtr cur) {
  525:     htmlNodeDumpFileFormat(out, doc, cur, NULL, 1);
  526: }
  527: 
  528: /**
  529:  * htmlDocDumpMemoryFormat:
  530:  * @cur:  the document
  531:  * @mem:  OUT: the memory pointer
  532:  * @size:  OUT: the memory length
  533:  * @format:  should formatting spaces been added
  534:  *
  535:  * Dump an HTML document in memory and return the xmlChar * and it's size.
  536:  * It's up to the caller to free the memory.
  537:  */
  538: void
  539: htmlDocDumpMemoryFormat(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
  540:     xmlOutputBufferPtr buf;
  541:     xmlCharEncodingHandlerPtr handler = NULL;
  542:     const char *encoding;
  543: 
  544:     xmlInitParser();
  545: 
  546:     if ((mem == NULL) || (size == NULL))
  547:         return;
  548:     if (cur == NULL) {
  549: 	*mem = NULL;
  550: 	*size = 0;
  551: 	return;
  552:     }
  553: 
  554:     encoding = (const char *) htmlGetMetaEncoding(cur);
  555: 
  556:     if (encoding != NULL) {
  557: 	xmlCharEncoding enc;
  558: 
  559: 	enc = xmlParseCharEncoding(encoding);
  560: 	if (enc != cur->charset) {
  561: 	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
  562: 		/*
  563: 		 * Not supported yet
  564: 		 */
  565: 		*mem = NULL;
  566: 		*size = 0;
  567: 		return;
  568: 	    }
  569: 
  570: 	    handler = xmlFindCharEncodingHandler(encoding);
  571: 	    if (handler == NULL)
  572:                 htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
  573: 
  574: 	} else {
  575: 	    handler = xmlFindCharEncodingHandler(encoding);
  576: 	}
  577:     }
  578: 
  579:     /*
  580:      * Fallback to HTML or ASCII when the encoding is unspecified
  581:      */
  582:     if (handler == NULL)
  583: 	handler = xmlFindCharEncodingHandler("HTML");
  584:     if (handler == NULL)
  585: 	handler = xmlFindCharEncodingHandler("ascii");
  586: 
  587:     buf = xmlAllocOutputBufferInternal(handler);
  588:     if (buf == NULL) {
  589: 	*mem = NULL;
  590: 	*size = 0;
  591: 	return;
  592:     }
  593: 
  594:     htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
  595: 
  596:     xmlOutputBufferFlush(buf);
  597:     if (buf->conv != NULL) {
  598: 	*size = buf->conv->use;
  599: 	*mem = xmlStrndup(buf->conv->content, *size);
  600:     } else {
  601: 	*size = buf->buffer->use;
  602: 	*mem = xmlStrndup(buf->buffer->content, *size);
  603:     }
  604:     (void)xmlOutputBufferClose(buf);
  605: }
  606: 
  607: /**
  608:  * htmlDocDumpMemory:
  609:  * @cur:  the document
  610:  * @mem:  OUT: the memory pointer
  611:  * @size:  OUT: the memory length
  612:  *
  613:  * Dump an HTML document in memory and return the xmlChar * and it's size.
  614:  * It's up to the caller to free the memory.
  615:  */
  616: void
  617: htmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
  618: 	htmlDocDumpMemoryFormat(cur, mem, size, 1);
  619: }
  620: 
  621: 
  622: /************************************************************************
  623:  *									*
  624:  *   		Dumping HTML tree content to an I/O output buffer	*
  625:  *									*
  626:  ************************************************************************/
  627: 
  628: void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
  629: 
  630: /**
  631:  * htmlDtdDumpOutput:
  632:  * @buf:  the HTML buffer output
  633:  * @doc:  the document
  634:  * @encoding:  the encoding string
  635:  * 
  636:  * TODO: check whether encoding is needed
  637:  *
  638:  * Dump the HTML document DTD, if any.
  639:  */
  640: static void
  641: htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
  642: 	          const char *encoding ATTRIBUTE_UNUSED) {
  643:     xmlDtdPtr cur = doc->intSubset;
  644: 
  645:     if (cur == NULL) {
  646: 	htmlSaveErr(XML_SAVE_NO_DOCTYPE, (xmlNodePtr) doc, NULL);
  647: 	return;
  648:     }
  649:     xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
  650:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  651:     if (cur->ExternalID != NULL) {
  652: 	xmlOutputBufferWriteString(buf, " PUBLIC ");
  653: 	xmlBufferWriteQuotedString(buf->buffer, cur->ExternalID);
  654: 	if (cur->SystemID != NULL) {
  655: 	    xmlOutputBufferWriteString(buf, " ");
  656: 	    xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
  657: 	} 
  658:     }  else if (cur->SystemID != NULL) {
  659: 	xmlOutputBufferWriteString(buf, " SYSTEM ");
  660: 	xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
  661:     }
  662:     xmlOutputBufferWriteString(buf, ">\n");
  663: }
  664: 
  665: /**
  666:  * htmlAttrDumpOutput:
  667:  * @buf:  the HTML buffer output
  668:  * @doc:  the document
  669:  * @cur:  the attribute pointer
  670:  * @encoding:  the encoding string
  671:  *
  672:  * Dump an HTML attribute
  673:  */
  674: static void
  675: htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
  676: 	           const char *encoding ATTRIBUTE_UNUSED) {
  677:     xmlChar *value;
  678: 
  679:     /*
  680:      * TODO: The html output method should not escape a & character
  681:      *       occurring in an attribute value immediately followed by
  682:      *       a { character (see Section B.7.1 of the HTML 4.0 Recommendation).
  683:      */
  684: 
  685:     if (cur == NULL) {
  686: 	return;
  687:     }
  688:     xmlOutputBufferWriteString(buf, " ");
  689:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  690:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  691: 	xmlOutputBufferWriteString(buf, ":");
  692:     }
  693:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  694:     if ((cur->children != NULL) && (!htmlIsBooleanAttr(cur->name))) {
  695: 	value = xmlNodeListGetString(doc, cur->children, 0);
  696: 	if (value) {
  697: 	    xmlOutputBufferWriteString(buf, "=");
  698: 	    if ((cur->ns == NULL) && (cur->parent != NULL) &&
  699: 		(cur->parent->ns == NULL) &&
  700: 		((!xmlStrcasecmp(cur->name, BAD_CAST "href")) ||
  701: 	         (!xmlStrcasecmp(cur->name, BAD_CAST "action")) ||
  702: 		 (!xmlStrcasecmp(cur->name, BAD_CAST "src")) ||
  703: 		 ((!xmlStrcasecmp(cur->name, BAD_CAST "name")) &&
  704: 		  (!xmlStrcasecmp(cur->parent->name, BAD_CAST "a"))))) {
  705: 		xmlChar *escaped;
  706: 		xmlChar *tmp = value;
  707: 
  708: 		while (IS_BLANK_CH(*tmp)) tmp++;
  709: 
  710: 		escaped = xmlURIEscapeStr(tmp, BAD_CAST"@/:=?;#%&,+");
  711: 		if (escaped != NULL) {
  712: 		    xmlBufferWriteQuotedString(buf->buffer, escaped);
  713: 		    xmlFree(escaped);
  714: 		} else {
  715: 		    xmlBufferWriteQuotedString(buf->buffer, value);
  716: 		}
  717: 	    } else {
  718: 		xmlBufferWriteQuotedString(buf->buffer, value);
  719: 	    }
  720: 	    xmlFree(value);
  721: 	} else  {
  722: 	    xmlOutputBufferWriteString(buf, "=\"\"");
  723: 	}
  724:     }
  725: }
  726: 
  727: /**
  728:  * htmlAttrListDumpOutput:
  729:  * @buf:  the HTML buffer output
  730:  * @doc:  the document
  731:  * @cur:  the first attribute pointer
  732:  * @encoding:  the encoding string
  733:  *
  734:  * Dump a list of HTML attributes
  735:  */
  736: static void
  737: htmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
  738:     if (cur == NULL) {
  739: 	return;
  740:     }
  741:     while (cur != NULL) {
  742:         htmlAttrDumpOutput(buf, doc, cur, encoding);
  743: 	cur = cur->next;
  744:     }
  745: }
  746: 
  747: 
  748: 
  749: /**
  750:  * htmlNodeListDumpOutput:
  751:  * @buf:  the HTML buffer output
  752:  * @doc:  the document
  753:  * @cur:  the first node
  754:  * @encoding:  the encoding string
  755:  * @format:  should formatting spaces been added
  756:  *
  757:  * Dump an HTML node list, recursive behaviour,children are printed too.
  758:  */
  759: static void
  760: htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
  761: 	               xmlNodePtr cur, const char *encoding, int format) {
  762:     if (cur == NULL) {
  763: 	return;
  764:     }
  765:     while (cur != NULL) {
  766:         htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
  767: 	cur = cur->next;
  768:     }
  769: }
  770: 
  771: /**
  772:  * htmlNodeDumpFormatOutput:
  773:  * @buf:  the HTML buffer output
  774:  * @doc:  the document
  775:  * @cur:  the current node
  776:  * @encoding:  the encoding string
  777:  * @format:  should formatting spaces been added
  778:  *
  779:  * Dump an HTML node, recursive behaviour,children are printed too.
  780:  */
  781: void
  782: htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
  783: 	                 xmlNodePtr cur, const char *encoding, int format) {
  784:     const htmlElemDesc * info;
  785: 
  786:     xmlInitParser();
  787: 
  788:     if ((cur == NULL) || (buf == NULL)) {
  789: 	return;
  790:     }
  791:     /*
  792:      * Special cases.
  793:      */
  794:     if (cur->type == XML_DTD_NODE)
  795: 	return;
  796:     if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
  797:         (cur->type == XML_DOCUMENT_NODE)){
  798: 	htmlDocContentDumpOutput(buf, (xmlDocPtr) cur, encoding);
  799: 	return;
  800:     }
  801:     if (cur->type == XML_ATTRIBUTE_NODE) {
  802:         htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur, encoding);
  803: 	return;
  804:     }
  805:     if (cur->type == HTML_TEXT_NODE) {
  806: 	if (cur->content != NULL) {
  807: 	    if (((cur->name == (const xmlChar *)xmlStringText) ||
  808: 		 (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
  809: 		((cur->parent == NULL) ||
  810: 		 ((xmlStrcasecmp(cur->parent->name, BAD_CAST "script")) &&
  811: 		  (xmlStrcasecmp(cur->parent->name, BAD_CAST "style"))))) {
  812: 		xmlChar *buffer;
  813: 
  814: 		buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
  815: 		if (buffer != NULL) {
  816: 		    xmlOutputBufferWriteString(buf, (const char *)buffer);
  817: 		    xmlFree(buffer);
  818: 		}
  819: 	    } else {
  820: 		xmlOutputBufferWriteString(buf, (const char *)cur->content);
  821: 	    }
  822: 	}
  823: 	return;
  824:     }
  825:     if (cur->type == HTML_COMMENT_NODE) {
  826: 	if (cur->content != NULL) {
  827: 	    xmlOutputBufferWriteString(buf, "<!--");
  828: 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
  829: 	    xmlOutputBufferWriteString(buf, "-->");
  830: 	}
  831: 	return;
  832:     }
  833:     if (cur->type == HTML_PI_NODE) {
  834: 	if (cur->name == NULL)
  835: 	    return;
  836: 	xmlOutputBufferWriteString(buf, "<?");
  837: 	xmlOutputBufferWriteString(buf, (const char *)cur->name);
  838: 	if (cur->content != NULL) {
  839: 	    xmlOutputBufferWriteString(buf, " ");
  840: 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
  841: 	}
  842: 	xmlOutputBufferWriteString(buf, ">");
  843: 	return;
  844:     }
  845:     if (cur->type == HTML_ENTITY_REF_NODE) {
  846:         xmlOutputBufferWriteString(buf, "&");
  847: 	xmlOutputBufferWriteString(buf, (const char *)cur->name);
  848:         xmlOutputBufferWriteString(buf, ";");
  849: 	return;
  850:     }
  851:     if (cur->type == HTML_PRESERVE_NODE) {
  852: 	if (cur->content != NULL) {
  853: 	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
  854: 	}
  855: 	return;
  856:     }
  857: 
  858:     /*
  859:      * Get specific HTML info for that node.
  860:      */
  861:     if (cur->ns == NULL)
  862: 	info = htmlTagLookup(cur->name);
  863:     else
  864: 	info = NULL;
  865: 
  866:     xmlOutputBufferWriteString(buf, "<");
  867:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  868:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  869: 	xmlOutputBufferWriteString(buf, ":");
  870:     }
  871:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  872:     if (cur->nsDef)
  873: 	xmlNsListDumpOutput(buf, cur->nsDef);
  874:     if (cur->properties != NULL)
  875:         htmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
  876: 
  877:     if ((info != NULL) && (info->empty)) {
  878:         xmlOutputBufferWriteString(buf, ">");
  879: 	if ((format) && (!info->isinline) && (cur->next != NULL)) {
  880: 	    if ((cur->next->type != HTML_TEXT_NODE) &&
  881: 		(cur->next->type != HTML_ENTITY_REF_NODE) &&
  882: 		(cur->parent != NULL) &&
  883: 		(cur->parent->name != NULL) &&
  884: 		(cur->parent->name[0] != 'p')) /* p, pre, param */
  885: 		xmlOutputBufferWriteString(buf, "\n");
  886: 	}
  887: 	return;
  888:     }
  889:     if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
  890: 	(cur->children == NULL)) {
  891:         if ((info != NULL) && (info->saveEndTag != 0) &&
  892: 	    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
  893: 	    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
  894: 	    xmlOutputBufferWriteString(buf, ">");
  895: 	} else {
  896: 	    xmlOutputBufferWriteString(buf, "></");
  897:             if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  898:                 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  899:                 xmlOutputBufferWriteString(buf, ":");
  900:             }
  901: 	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
  902: 	    xmlOutputBufferWriteString(buf, ">");
  903: 	}
  904: 	if ((format) && (cur->next != NULL) &&
  905:             (info != NULL) && (!info->isinline)) {
  906: 	    if ((cur->next->type != HTML_TEXT_NODE) &&
  907: 		(cur->next->type != HTML_ENTITY_REF_NODE) &&
  908: 		(cur->parent != NULL) &&
  909: 		(cur->parent->name != NULL) &&
  910: 		(cur->parent->name[0] != 'p')) /* p, pre, param */
  911: 		xmlOutputBufferWriteString(buf, "\n");
  912: 	}
  913: 	return;
  914:     }
  915:     xmlOutputBufferWriteString(buf, ">");
  916:     if ((cur->type != XML_ELEMENT_NODE) &&
  917: 	(cur->content != NULL)) {
  918: 	    /*
  919: 	     * Uses the OutputBuffer property to automatically convert
  920: 	     * invalids to charrefs
  921: 	     */
  922: 
  923:             xmlOutputBufferWriteString(buf, (const char *) cur->content);
  924:     }
  925:     if (cur->children != NULL) {
  926:         if ((format) && (info != NULL) && (!info->isinline) &&
  927: 	    (cur->children->type != HTML_TEXT_NODE) &&
  928: 	    (cur->children->type != HTML_ENTITY_REF_NODE) &&
  929: 	    (cur->children != cur->last) &&
  930: 	    (cur->name != NULL) &&
  931: 	    (cur->name[0] != 'p')) /* p, pre, param */
  932: 	    xmlOutputBufferWriteString(buf, "\n");
  933: 	htmlNodeListDumpOutput(buf, doc, cur->children, encoding, format);
  934:         if ((format) && (info != NULL) && (!info->isinline) &&
  935: 	    (cur->last->type != HTML_TEXT_NODE) &&
  936: 	    (cur->last->type != HTML_ENTITY_REF_NODE) &&
  937: 	    (cur->children != cur->last) &&
  938: 	    (cur->name != NULL) &&
  939: 	    (cur->name[0] != 'p')) /* p, pre, param */
  940: 	    xmlOutputBufferWriteString(buf, "\n");
  941:     }
  942:     xmlOutputBufferWriteString(buf, "</");
  943:     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
  944:         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
  945: 	xmlOutputBufferWriteString(buf, ":");
  946:     }
  947:     xmlOutputBufferWriteString(buf, (const char *)cur->name);
  948:     xmlOutputBufferWriteString(buf, ">");
  949:     if ((format) && (info != NULL) && (!info->isinline) &&
  950: 	(cur->next != NULL)) {
  951:         if ((cur->next->type != HTML_TEXT_NODE) &&
  952: 	    (cur->next->type != HTML_ENTITY_REF_NODE) &&
  953: 	    (cur->parent != NULL) &&
  954: 	    (cur->parent->name != NULL) &&
  955: 	    (cur->parent->name[0] != 'p')) /* p, pre, param */
  956: 	    xmlOutputBufferWriteString(buf, "\n");
  957:     }
  958: }
  959: 
  960: /**
  961:  * htmlNodeDumpOutput:
  962:  * @buf:  the HTML buffer output
  963:  * @doc:  the document
  964:  * @cur:  the current node
  965:  * @encoding:  the encoding string
  966:  *
  967:  * Dump an HTML node, recursive behaviour,children are printed too,
  968:  * and formatting returns/spaces are added.
  969:  */
  970: void
  971: htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
  972: 	           xmlNodePtr cur, const char *encoding) {
  973:     htmlNodeDumpFormatOutput(buf, doc, cur, encoding, 1);
  974: }
  975: 
  976: /**
  977:  * htmlDocContentDumpFormatOutput:
  978:  * @buf:  the HTML buffer output
  979:  * @cur:  the document
  980:  * @encoding:  the encoding string
  981:  * @format:  should formatting spaces been added
  982:  *
  983:  * Dump an HTML document.
  984:  */
  985: void
  986: htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
  987: 	                       const char *encoding, int format) {
  988:     int type;
  989: 
  990:     xmlInitParser();
  991: 
  992:     if ((buf == NULL) || (cur == NULL))
  993:         return;
  994: 
  995:     /*
  996:      * force to output the stuff as HTML, especially for entities
  997:      */
  998:     type = cur->type;
  999:     cur->type = XML_HTML_DOCUMENT_NODE;
 1000:     if (cur->intSubset != NULL) {
 1001:         htmlDtdDumpOutput(buf, cur, NULL);
 1002:     }
 1003:     if (cur->children != NULL) {
 1004:         htmlNodeListDumpOutput(buf, cur, cur->children, encoding, format);
 1005:     }
 1006:     xmlOutputBufferWriteString(buf, "\n");
 1007:     cur->type = (xmlElementType) type;
 1008: }
 1009: 
 1010: /**
 1011:  * htmlDocContentDumpOutput:
 1012:  * @buf:  the HTML buffer output
 1013:  * @cur:  the document
 1014:  * @encoding:  the encoding string
 1015:  *
 1016:  * Dump an HTML document. Formating return/spaces are added.
 1017:  */
 1018: void
 1019: htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
 1020: 	                 const char *encoding) {
 1021:     htmlDocContentDumpFormatOutput(buf, cur, encoding, 1);
 1022: }
 1023: 
 1024: /************************************************************************
 1025:  *									*
 1026:  *		Saving functions front-ends				*
 1027:  *									*
 1028:  ************************************************************************/
 1029: 
 1030: /**
 1031:  * htmlDocDump:
 1032:  * @f:  the FILE*
 1033:  * @cur:  the document
 1034:  *
 1035:  * Dump an HTML document to an open FILE.
 1036:  *
 1037:  * returns: the number of byte written or -1 in case of failure.
 1038:  */
 1039: int
 1040: htmlDocDump(FILE *f, xmlDocPtr cur) {
 1041:     xmlOutputBufferPtr buf;
 1042:     xmlCharEncodingHandlerPtr handler = NULL;
 1043:     const char *encoding;
 1044:     int ret;
 1045: 
 1046:     xmlInitParser();
 1047: 
 1048:     if ((cur == NULL) || (f == NULL)) {
 1049: 	return(-1);
 1050:     }
 1051: 
 1052:     encoding = (const char *) htmlGetMetaEncoding(cur);
 1053: 
 1054:     if (encoding != NULL) {
 1055: 	xmlCharEncoding enc;
 1056: 
 1057: 	enc = xmlParseCharEncoding(encoding);
 1058: 	if (enc != cur->charset) {
 1059: 	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
 1060: 		/*
 1061: 		 * Not supported yet
 1062: 		 */
 1063: 		return(-1);
 1064: 	    }
 1065: 
 1066: 	    handler = xmlFindCharEncodingHandler(encoding);
 1067: 	    if (handler == NULL)
 1068: 		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
 1069: 	} else {
 1070: 	    handler = xmlFindCharEncodingHandler(encoding);
 1071: 	}
 1072:     }
 1073: 
 1074:     /*
 1075:      * Fallback to HTML or ASCII when the encoding is unspecified
 1076:      */
 1077:     if (handler == NULL)
 1078: 	handler = xmlFindCharEncodingHandler("HTML");
 1079:     if (handler == NULL)
 1080: 	handler = xmlFindCharEncodingHandler("ascii");
 1081: 
 1082:     buf = xmlOutputBufferCreateFile(f, handler);
 1083:     if (buf == NULL) return(-1);
 1084:     htmlDocContentDumpOutput(buf, cur, NULL);
 1085: 
 1086:     ret = xmlOutputBufferClose(buf);
 1087:     return(ret);
 1088: }
 1089: 
 1090: /**
 1091:  * htmlSaveFile:
 1092:  * @filename:  the filename (or URL)
 1093:  * @cur:  the document
 1094:  *
 1095:  * Dump an HTML document to a file. If @filename is "-" the stdout file is
 1096:  * used.
 1097:  * returns: the number of byte written or -1 in case of failure.
 1098:  */
 1099: int
 1100: htmlSaveFile(const char *filename, xmlDocPtr cur) {
 1101:     xmlOutputBufferPtr buf;
 1102:     xmlCharEncodingHandlerPtr handler = NULL;
 1103:     const char *encoding;
 1104:     int ret;
 1105: 
 1106:     if ((cur == NULL) || (filename == NULL))
 1107:         return(-1);
 1108:        
 1109:     xmlInitParser();
 1110: 
 1111:     encoding = (const char *) htmlGetMetaEncoding(cur);
 1112: 
 1113:     if (encoding != NULL) {
 1114: 	xmlCharEncoding enc;
 1115: 
 1116: 	enc = xmlParseCharEncoding(encoding);
 1117: 	if (enc != cur->charset) {
 1118: 	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
 1119: 		/*
 1120: 		 * Not supported yet
 1121: 		 */
 1122: 		return(-1);
 1123: 	    }
 1124: 
 1125: 	    handler = xmlFindCharEncodingHandler(encoding);
 1126: 	    if (handler == NULL)
 1127: 		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
 1128: 	}
 1129:     }
 1130: 
 1131:     /*
 1132:      * Fallback to HTML or ASCII when the encoding is unspecified
 1133:      */
 1134:     if (handler == NULL)
 1135: 	handler = xmlFindCharEncodingHandler("HTML");
 1136:     if (handler == NULL)
 1137: 	handler = xmlFindCharEncodingHandler("ascii");
 1138: 
 1139:     /* 
 1140:      * save the content to a temp buffer.
 1141:      */
 1142:     buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
 1143:     if (buf == NULL) return(0);
 1144: 
 1145:     htmlDocContentDumpOutput(buf, cur, NULL);
 1146: 
 1147:     ret = xmlOutputBufferClose(buf);
 1148:     return(ret);
 1149: }
 1150: 
 1151: /**
 1152:  * htmlSaveFileFormat:
 1153:  * @filename:  the filename
 1154:  * @cur:  the document
 1155:  * @format:  should formatting spaces been added
 1156:  * @encoding: the document encoding
 1157:  *
 1158:  * Dump an HTML document to a file using a given encoding.
 1159:  * 
 1160:  * returns: the number of byte written or -1 in case of failure.
 1161:  */
 1162: int
 1163: htmlSaveFileFormat(const char *filename, xmlDocPtr cur,
 1164: 	           const char *encoding, int format) {
 1165:     xmlOutputBufferPtr buf;
 1166:     xmlCharEncodingHandlerPtr handler = NULL;
 1167:     int ret;
 1168: 
 1169:     if ((cur == NULL) || (filename == NULL))
 1170:         return(-1);
 1171: 
 1172:     xmlInitParser();
 1173: 
 1174:     if (encoding != NULL) {
 1175: 	xmlCharEncoding enc;
 1176: 
 1177: 	enc = xmlParseCharEncoding(encoding);
 1178: 	if (enc != cur->charset) {
 1179: 	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
 1180: 		/*
 1181: 		 * Not supported yet
 1182: 		 */
 1183: 		return(-1);
 1184: 	    }
 1185: 
 1186: 	    handler = xmlFindCharEncodingHandler(encoding);
 1187: 	    if (handler == NULL)
 1188: 		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
 1189: 	}
 1190:         htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
 1191:     } else {
 1192: 	htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
 1193:     }
 1194: 
 1195:     /*
 1196:      * Fallback to HTML or ASCII when the encoding is unspecified
 1197:      */
 1198:     if (handler == NULL)
 1199: 	handler = xmlFindCharEncodingHandler("HTML");
 1200:     if (handler == NULL)
 1201: 	handler = xmlFindCharEncodingHandler("ascii");
 1202: 
 1203:     /* 
 1204:      * save the content to a temp buffer.
 1205:      */
 1206:     buf = xmlOutputBufferCreateFilename(filename, handler, 0);
 1207:     if (buf == NULL) return(0);
 1208: 
 1209:     htmlDocContentDumpFormatOutput(buf, cur, encoding, format);
 1210: 
 1211:     ret = xmlOutputBufferClose(buf);
 1212:     return(ret);
 1213: }
 1214: 
 1215: /**
 1216:  * htmlSaveFileEnc:
 1217:  * @filename:  the filename
 1218:  * @cur:  the document
 1219:  * @encoding: the document encoding
 1220:  *
 1221:  * Dump an HTML document to a file using a given encoding
 1222:  * and formatting returns/spaces are added.
 1223:  * 
 1224:  * returns: the number of byte written or -1 in case of failure.
 1225:  */
 1226: int
 1227: htmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
 1228:     return(htmlSaveFileFormat(filename, cur, encoding, 1));
 1229: }
 1230: 
 1231: #endif /* LIBXML_OUTPUT_ENABLED */
 1232: 
 1233: #define bottom_HTMLtree
 1234: #include "elfgcchack.h"
 1235: #endif /* LIBXML_HTML_ENABLED */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>