SF.net SVN: geany-plugins:[882] trunk/geany-plugins
ctabin at users.sourceforge.net
ctabin at xxxxx
Mon Aug 10 10:34:22 UTC 2009
Revision: 882
http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=882&view=rev
Author: ctabin
Date: 2009-08-10 10:34:22 +0000 (Mon, 10 Aug 2009)
Log Message:
-----------
The pretty-printer source code moved to geany-plugins folder
Added Paths:
-----------
trunk/geany-plugins/pretty-printer/
trunk/geany-plugins/pretty-printer/src/
trunk/geany-plugins/pretty-printer/src/Plugin.c
trunk/geany-plugins/pretty-printer/src/PrettyPrinter.c
trunk/geany-plugins/pretty-printer/src/PrettyPrinter.h
Added: trunk/geany-plugins/pretty-printer/src/Plugin.c
===================================================================
--- trunk/geany-plugins/pretty-printer/src/Plugin.c (rev 0)
+++ trunk/geany-plugins/pretty-printer/src/Plugin.c 2009-08-10 10:34:22 UTC (rev 882)
@@ -0,0 +1,147 @@
+/**
+ * Written by Cédric Tabin
+ * http://www.astorm.ch/
+ * Version 1.0 - 08.08.2009
+ *
+ * Code under licence GPLv2
+ * Geany - http://www.geany.org/
+ */
+
+/*
+ * Basic plugin structure, based of Geany Plugin howto :
+ * http://www.geany.org/manual/reference/howto.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <geany.h>
+#include <ui_utils.h>
+#include <plugindata.h>
+#include <editor.h>
+#include <document.h>
+#include <filetypes.h>
+#include <geanyfunctions.h>
+#include <Scintilla.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "PrettyPrinter.c"
+
+GeanyPlugin* geany_plugin;
+GeanyData* geany_data;
+GeanyFunctions* geany_functions;
+PrettyPrintingOptions* prettyPrintingOptions;
+
+//plugin information
+PLUGIN_VERSION_CHECK(130)
+PLUGIN_SET_INFO("XML Formatter", "Format an XML file",
+ "1.0", "Cédric Tabin - http://www.astorm.ch");
+
+static GtkWidget *main_menu_item = NULL;
+
+static void item_activate_cb(GtkMenuItem *menuitem, gpointer gdata)
+{
+ //default printing options
+ if (prettyPrintingOptions == NULL) { prettyPrintingOptions = createDefaultPrettyPrintingOptions(); }
+
+ //retrieves the current document
+ GeanyDocument* doc = document_get_current();
+ GeanyEditor* editor = doc->editor;
+ ScintillaObject* sco = editor->sci;
+
+ //allocate a new pointer
+ int length = sci_get_length(sco)+1;
+ char* buffer = (char*)malloc(length*sizeof(char));
+ if (buffer == NULL) { exit(-1); } //malloc error
+
+ //retrieves the text
+ sci_get_text(sco, length, buffer);
+
+ //checks if the data is an XML format
+ xmlDoc* xmlDoc = xmlParseDoc((unsigned char*)buffer);
+
+ if(xmlDoc == NULL) //this is not a valid xml
+ {
+ dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Unable to parse the content as XML.");
+ return;
+ }
+
+ //process pretty-printing
+ int result = processXMLPrettyPrinting(&buffer, &length, prettyPrintingOptions);
+ if (result != 0)
+ {
+ dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Unable to process PrettyPrinting on the specified XML because some features are not supported.");
+ return;
+ }
+
+ //updates the document
+ sci_set_text(sco, buffer);
+
+ //sets the type
+ GeanyFiletype* fileType = filetypes_index(GEANY_FILETYPES_XML);
+ document_set_filetype(doc, fileType);
+
+ //free all
+ xmlFreeDoc(xmlDoc);
+}
+
+void plugin_init(GeanyData *data)
+{
+ //Initializes the libxml2
+ LIBXML_TEST_VERSION
+
+ //put the menu into the Tools
+ main_menu_item = gtk_menu_item_new_with_mnemonic("XML Formatter");
+ gtk_widget_show(main_menu_item);
+ gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), main_menu_item);
+
+ //add activation callback
+ g_signal_connect(main_menu_item, "activate", G_CALLBACK(item_activate_cb), NULL);
+}
+
+void plugin_cleanup(void)
+{
+ //destroys the plugin
+ gtk_widget_destroy(main_menu_item);
+}
+
+GtkWidget* plugin_configure(GtkDialog * dialog)
+{
+ //default printing options
+ if (prettyPrintingOptions == NULL) { prettyPrintingOptions = createDefaultPrettyPrintingOptions(); }
+
+ GtkWidget* globalBox = gtk_hbox_new(TRUE, 4);
+ GtkWidget* rightBox = gtk_vbox_new(FALSE, 6);
+ GtkWidget* centerBox = gtk_vbox_new(FALSE, 6);
+ GtkWidget* leftBox = gtk_vbox_new(FALSE, 6);
+
+ GtkWidget* textLabel = gtk_label_new("Text nodes");
+ GtkWidget* textOneLine = gtk_check_button_new_with_label("One line");
+ GtkWidget* textInline = gtk_check_button_new_with_label("Inline");
+
+ GtkWidget* cdataLabel = gtk_label_new("CDATA nodes");
+ GtkWidget* cdataOneLine = gtk_check_button_new_with_label("One line");
+ GtkWidget* cdataInline = gtk_check_button_new_with_label("Inline");
+
+ GtkWidget* commentLabel = gtk_label_new("Comments");
+ GtkWidget* commentOneLine = gtk_check_button_new_with_label("One line");
+ GtkWidget* commentInline = gtk_check_button_new_with_label("Inline");
+
+ gtk_box_pack_start(GTK_BOX(globalBox), leftBox, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(globalBox), centerBox, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(globalBox), rightBox, FALSE, FALSE, 3);
+
+ gtk_box_pack_start(GTK_BOX(leftBox), textLabel, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(centerBox), textOneLine, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(rightBox), textInline, FALSE, FALSE, 3);
+
+ gtk_box_pack_start(GTK_BOX(leftBox), cdataLabel, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(centerBox), cdataOneLine, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(rightBox), cdataInline, FALSE, FALSE, 3);
+
+ gtk_box_pack_start(GTK_BOX(leftBox), commentLabel, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(centerBox), commentOneLine, FALSE, FALSE, 3);
+ gtk_box_pack_start(GTK_BOX(rightBox), commentInline, FALSE, FALSE, 3);
+
+ gtk_widget_show_all(globalBox);
+ return globalBox;
+}
Added: trunk/geany-plugins/pretty-printer/src/PrettyPrinter.c
===================================================================
--- trunk/geany-plugins/pretty-printer/src/PrettyPrinter.c (rev 0)
+++ trunk/geany-plugins/pretty-printer/src/PrettyPrinter.c 2009-08-10 10:34:22 UTC (rev 882)
@@ -0,0 +1,744 @@
+/**
+ * Written by Cédric Tabin
+ * http://www.astorm.ch/
+ * Version 1.0 - 08.08.2009
+ *
+ * Code under licence GPLv2
+ * Geany - http://www.geany.org/
+ */
+
+#include "PrettyPrinter.h"
+
+//======================= FUNCTIONS ====================================================================
+
+//xml pretty printing functions
+static void putCharInBuffer(char charToAdd); //put a char into the new char buffer
+static void putCharsInBuffer(char* charsToAdd); //put the chars into the new char buffer
+static void putNextCharsInBuffer(int nbChars); //put the next nbChars of the input buffer into the new buffer
+static int readWhites(); //read the next whites into the input buffer
+static char readNextChar(); //read the next char into the input buffer;
+static char getNextChar(); //returns the next char but do not increase the input buffer index (use readNextChar for that)
+static char getPreviousInsertedChar(); //returns the last inserted char into the new buffer
+static boolean isWhite(char c); //check if the specified char is a white
+static boolean isLineBreak(char c); //check if the specified char is a new line
+static int putNewLine(); //put a new line into the new char buffer with the correct number of whites (indentation)
+static boolean isInlineNodeAllowed(); //check if it is possible to have an inline node
+static void resetBackwardIndentation(boolean resetLineBreak); //reset the indentation for the current depth (just reset the index in fact)
+
+//specific parsing functions
+static int processElements(); //returns the number of elements processed
+static void processElementAttribute(); //process on attribute of a node
+static void processElementAttributes(); //process all the attributes of a node
+static void processHeader(); //process the header <?xml version="..." ?>
+static void processNode(); //process an XML node
+static void processTextNode(); //process a text node
+static void processComment(); //process a comment
+static void processCDATA(); //process a CDATA node
+static void processDoctype(); //process a DOCTYPE node
+static void processDoctypeElement(); //process a DOCTYPE ELEMENT node
+
+//debug function
+static void printDebugStatus(); //just print some variables into the console for debugging
+
+//============================================ PRIVATE PROPERTIES ======================================
+
+//those are variables that are shared by the functions and
+//shouldn't be altered.
+
+static int result; //result of the pretty printing
+static char* xmlPrettyPrinted; //new buffer for the formatted XML
+static int xmlPrettyPrintedLength; //buffer size
+static int xmlPrettyPrintedIndex; //buffer index (position of the next char to insert)
+static char* inputBuffer; //input buffer
+static int inputBufferLength; //input buffer size
+static int inputBufferIndex; //input buffer index (position of the next char to read into the input string)
+static int currentDepth; //current depth (for indentation)
+static char* currentNodeName; //current node name
+static boolean appendIndentation; //if the indentation must be added (with a line break before)
+static boolean lastNodeOpen; //defines if the last action was a not opening or not
+static PrettyPrintingOptions* options; //options of PrettyPrinting
+
+//============================================ GENERAL FUNCTIONS =======================================
+
+int processXMLPrettyPrinting(char** buffer, int* length, PrettyPrintingOptions* ppOptions)
+{
+ //empty buffer, nothing to process
+ if (*length == 0) { return PRETTY_PRINTING_EMPTY_XML; }
+ if (buffer == NULL || *buffer == NULL) { return PRETTY_PRINTING_EMPTY_XML; }
+
+ //initialize the variables
+ result = PRETTY_PRINTING_SUCCESS;
+ boolean freeOptions = FALSE;
+ if (ppOptions == NULL) { ppOptions = createDefaultPrettyPrintingOptions(); freeOptions = TRUE; }
+ options = ppOptions;
+
+ currentNodeName = NULL;
+ appendIndentation = FALSE;
+ lastNodeOpen = FALSE;
+ xmlPrettyPrintedIndex = 0;
+ inputBufferIndex = 0;
+ currentDepth = -1;
+
+ inputBuffer = *buffer;
+ inputBufferLength = *length;
+
+ xmlPrettyPrintedLength = *length;
+ xmlPrettyPrinted = (char*)malloc(sizeof(char)*(*length));
+ if (xmlPrettyPrinted == NULL) { exit(PRETTY_PRINTING_MALLOC_ERROR); }
+
+ //go to the first char
+ readWhites();
+
+ //process the pretty-printing
+ processElements();
+
+ //close the buffer
+ putCharInBuffer('\0');
+
+ //adjust the final size
+ xmlPrettyPrinted = realloc(xmlPrettyPrinted, xmlPrettyPrintedIndex);
+ if (xmlPrettyPrinted == NULL) { exit(PRETTY_PRINTING_MALLOC_ERROR); }
+
+ //freeing the unused values
+ if (freeOptions) { free(options); }
+
+ //if success, then update the values
+ if (result == PRETTY_PRINTING_SUCCESS)
+ {
+ free(*buffer);
+ *buffer = xmlPrettyPrinted;
+ *length = xmlPrettyPrintedIndex-2; //the '\0' is not in the length
+ }
+ //else clean the other values
+ else
+ {
+ free(xmlPrettyPrinted);
+ }
+
+ //updating the pointers for the using into the caller function
+ xmlPrettyPrinted = NULL; //avoid reference
+ inputBuffer = NULL; //avoid reference
+ currentNodeName = NULL; //avoid reference
+ options = NULL; //avoid reference
+
+ //and finally the result
+ return result;
+}
+
+PrettyPrintingOptions* createDefaultPrettyPrintingOptions()
+{
+ PrettyPrintingOptions* options = (PrettyPrintingOptions*)malloc(sizeof(PrettyPrintingOptions));
+ if (options == NULL) { fprintf(stderr, "createDefaultPrettyPrintingOptions : Unable to allocate memory"); return NULL; }
+
+ options->indentChar = ' ';
+ options->indentLength = 2;
+ options->oneLineText = TRUE;
+ options->inlineText = TRUE;
+ options->oneLineComment = TRUE;
+ options->inlineComment = TRUE;
+ options->oneLineCdata = TRUE;
+ options->inlineCdata = TRUE;
+ options->emptyNodeStripping = TRUE;
+ options->emptyNodeStrippingSpace = TRUE;
+ options->forceEmptyNodeSplit = FALSE;
+ options->trimLeadingWhites = TRUE;
+ options->trimTrailingWhites = TRUE;
+
+ return options;
+}
+
+void putNextCharsInBuffer(int nbChars)
+{
+ for (int i=0 ; i<nbChars ; ++i)
+ {
+ char c = readNextChar();
+ putCharInBuffer(c);
+ }
+}
+
+void putCharInBuffer(char charToAdd)
+{
+ //check if the buffer is full and reallocation if needed
+ if (xmlPrettyPrintedIndex >= xmlPrettyPrintedLength)
+ {
+ if (charToAdd == '\0') { ++xmlPrettyPrintedLength; }
+ else { xmlPrettyPrintedLength += inputBufferLength; }
+ xmlPrettyPrinted = (char*)realloc(xmlPrettyPrinted, xmlPrettyPrintedLength);
+ if (xmlPrettyPrinted == NULL) { exit(PRETTY_PRINTING_MALLOC_ERROR); }
+ }
+
+ //putting the char and increase the index for the next one
+ xmlPrettyPrinted[xmlPrettyPrintedIndex] = charToAdd;
+ ++xmlPrettyPrintedIndex;
+}
+
+void putCharsInBuffer(char* charsToAdd)
+{
+ int index = 0;
+ while (charsToAdd[index] != '\0')
+ {
+ putCharInBuffer(charsToAdd[index]);
+ ++index;
+ }
+}
+
+char getPreviousInsertedChar()
+{
+ return xmlPrettyPrinted[xmlPrettyPrintedIndex-1];
+}
+
+int putNewLine()
+{
+ putCharInBuffer('\n');
+ int spaces = currentDepth*options->indentLength;
+ for(int i=0 ; i<spaces ; ++i)
+ {
+ putCharInBuffer(options->indentChar);
+ }
+
+ return spaces;
+}
+
+char getNextChar()
+{
+ return inputBuffer[inputBufferIndex];
+}
+
+char readNextChar()
+{
+ return inputBuffer[inputBufferIndex++];
+}
+
+int readWhites()
+{
+ int counter = 0;
+ while(isWhite(inputBuffer[inputBufferIndex]))
+ {
+ ++counter;
+ ++inputBufferIndex;
+ }
+
+ return counter;
+}
+
+boolean isWhite(char c)
+{
+ if (c == ' ') return TRUE;
+ if (c == '\t') return TRUE;
+ if (c == '\r') return TRUE;
+ if (c == '\n') return TRUE;
+
+ return FALSE;
+}
+
+boolean isLineBreak(char c)
+{
+ if (c == '\n') return TRUE;
+ if (c == '\r') return TRUE;
+
+ return FALSE;
+}
+
+boolean isInlineNodeAllowed()
+{
+ //the last action was not an opening => inline not allowed
+ if (!lastNodeOpen) { return FALSE; }
+
+ int firstChar = getNextChar(); //should be '<' or we are in a text node
+ int secondChar = inputBuffer[inputBufferIndex+1]; //should be '!'
+ int thirdChar = inputBuffer[inputBufferIndex+2]; //should be '-' or '['
+
+ int index = inputBufferIndex+1;
+ if (firstChar == '<')
+ {
+ //another node is being open ==> no inline !
+ if (secondChar != '!') { return FALSE; }
+
+ //okay we are in a comment node, so read until it is closed
+
+ //select the closing char
+ char closingComment = '-';
+ if (thirdChar == '[') { closingComment = ']'; }
+
+ //read until closing
+ char oldChar = ' ';
+ index += 3; //that by pass meanless chars
+ boolean loop = TRUE;
+ while (loop)
+ {
+ char current = inputBuffer[index];
+ if (current == closingComment && oldChar == closingComment) { loop = FALSE; } //end of comment
+ oldChar = current;
+ ++index;
+ }
+
+ //okay now avoid blanks
+ // inputBuffer[index] is now '>'
+ ++index;
+ while (isWhite(inputBuffer[index])) { ++index; }
+ }
+ else
+ {
+ //this is a text node. Simply loop to the next '<'
+ while (inputBuffer[index] != '<') { ++index; }
+ }
+
+ //check what do we have now
+ char currentChar = inputBuffer[index];
+ if (currentChar == '<')
+ {
+ //check if that is a closing node
+ currentChar = inputBuffer[index+1];
+ if (currentChar == '/')
+ {
+ //as we are in a correct XML (so far...), if the node is being
+ //directly close, the inline is allowed !!!
+ return TRUE;
+ }
+ }
+
+ //inline not allowed...
+ return FALSE;
+}
+
+void resetBackwardIndentation(boolean resetLineBreak)
+{
+ xmlPrettyPrintedIndex -= (currentDepth*options->indentLength);
+ if (resetLineBreak) { --xmlPrettyPrintedIndex; }
+}
+
+//#########################################################################################################################################
+//-----------------------------------------------------------------------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------------------------------------------------------------------
+//=============================================================== NODE FUNCTIONS ==========================================================
+//-----------------------------------------------------------------------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------------------------------------------------------------------
+//#########################################################################################################################################
+
+int processElements()
+{
+ int counter = 0;
+ ++currentDepth;
+ boolean loop = TRUE;
+ while (loop && result == PRETTY_PRINTING_SUCCESS)
+ {
+ //strip unused whites
+ readWhites();
+
+ char nextChar = getNextChar();
+ if (nextChar == '\0') { return 0; } //no more data to read
+
+ //put a new line with indentation
+ if (appendIndentation) { putNewLine(); }
+
+ //always append indentation (but need to store the state)
+ boolean indentBackward = appendIndentation;
+ appendIndentation = TRUE;
+
+ //okay what do we have now ?
+ if (nextChar != '<')
+ {
+ //a simple text node
+ processTextNode();
+ ++counter;
+ }
+ else //some more check are needed
+ {
+ nextChar = inputBuffer[inputBufferIndex+1];
+ if (nextChar == '!')
+ {
+ char oneMore = inputBuffer[inputBufferIndex+2];
+ if (oneMore == '-') { processComment(); ++counter; } //a comment
+ else if (oneMore == '[') { processCDATA(); ++counter; } //cdata
+ else if (oneMore == 'D') { processDoctype(); ++counter; } //doctype <!DOCTYPE ... >
+ else if (oneMore == 'E') { processDoctypeElement(); ++counter; } //doctype element <!ELEMENT ... >
+ else { fprintf(stderr, "processElements : Invalid char '%c' afer '<!'", oneMore); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; }
+ }
+ else if (nextChar == '/')
+ {
+ //close a node => stop the loop !!
+ loop = FALSE;
+ if (indentBackward) { xmlPrettyPrintedIndex -= options->indentLength; } //INDEX HACKING
+ }
+ else if (nextChar == '?')
+ {
+ //this is a header
+ processHeader();
+ }
+ else
+ {
+ //a new node is open
+ processNode();
+ ++counter;
+ }
+ }
+ }
+
+ --currentDepth;
+ return counter;
+}
+
+void processElementAttribute()
+{
+ //process the attribute name
+ char nextChar = readNextChar();
+ while (nextChar != '=')
+ {
+ putCharInBuffer(nextChar);
+ nextChar = readNextChar();
+ }
+
+ putCharInBuffer(nextChar); //that's the '='
+
+ //read the simple quote or double quote and put it into the buffer
+ char quote = readNextChar();
+ putCharInBuffer(quote);
+
+ //process until the last quote
+ char value = readNextChar();
+ while(value != quote)
+ {
+ putCharInBuffer(value);
+ value = readNextChar();
+ }
+
+ //simply add the last quote
+ putCharInBuffer(quote);
+}
+
+void processElementAttributes()
+{
+ char current = getNextChar(); //should not be a white
+ if (isWhite(current)) { fprintf(stderr, "processElementAttributes : first char shouldn't be a white"); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+
+ boolean loop = TRUE;
+ while (loop)
+ {
+ readWhites(); //strip the whites
+
+ char next = getNextChar(); //don't read the last char => will be processed afterwards
+ if (next == '/') { loop = FALSE; } /* end of node */
+ else if (next == '>') { loop = FALSE; } /* end of tag */
+ else if (next == '?') { loop = FALSE; } /* end of header */
+ else
+ {
+ putCharInBuffer(' '); //put only one space to separate attributes
+ processElementAttribute();
+ }
+ }
+}
+
+void processHeader()
+{
+ int firstChar = inputBuffer[inputBufferIndex]; //should be '<'
+ int secondChar = inputBuffer[inputBufferIndex+1]; //must be '?'
+
+ if (firstChar != '<') { fprintf(stderr, "processHeader : first char should be '<' (not '%c')", firstChar); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; } /* what ?????? invalid xml !!! */
+ if (secondChar == '?')
+ {
+ putNextCharsInBuffer(2); //puts the '<' and '?' chars into the new buffer
+
+ while(!isWhite(getNextChar())) { putNextCharsInBuffer(1); }
+
+ readWhites();
+ processElementAttributes();
+ putNextCharsInBuffer(2); //puts the '?' and '>' chars into the new buffer
+ }
+}
+
+void processNode()
+{
+ int opening = readNextChar();
+ if (opening != '<') { fprintf(stderr, "processNode : The first char should be '<' (not '%c')", opening); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+ putCharInBuffer(opening);
+
+ //read the node name
+ int nodeNameLength = 0;
+ while (!isWhite(getNextChar()) && getNextChar() != '>' && getNextChar() != '/')
+ {
+ putNextCharsInBuffer(1);
+ ++nodeNameLength;
+ }
+
+ //store the name
+ char* nodeName = (char*)malloc(sizeof(char)*nodeNameLength+1);
+ if (nodeName == NULL) { exit(PRETTY_PRINTING_MALLOC_ERROR); }
+ nodeName[nodeNameLength] = '\0';
+ for (int i=0 ; i<nodeNameLength ; ++i)
+ {
+ int index = xmlPrettyPrintedIndex-nodeNameLength+i;
+ nodeName[i] = xmlPrettyPrinted[index];
+ }
+
+ currentNodeName = nodeName; //set the name for using in other methods
+ lastNodeOpen = TRUE;
+
+ //process the attributes
+ readWhites();
+ processElementAttributes();
+
+ //process the end of the tag
+ int subElementsProcessed = 0;
+ char nextChar = getNextChar(); //should be either '/' or '>'
+ if (nextChar == '/') //the node is being closed immediatly
+ {
+ //closing node directly
+ if (options->emptyNodeStripping || !options->forceEmptyNodeSplit)
+ {
+ if (options->emptyNodeStrippingSpace) { putCharInBuffer(' '); }
+ putNextCharsInBuffer(2);
+ }
+ //split the closing nodes
+ else
+ {
+ readNextChar(); //removing '/'
+ readNextChar(); //removing '>'
+
+ putCharInBuffer('>');
+ if (!options->inlineText) { putNewLine(); } //no inline text => new line !
+ putCharsInBuffer("</");
+ putCharsInBuffer(currentNodeName);
+ putCharInBuffer('>');
+ }
+
+ lastNodeOpen=FALSE;
+ return;
+ }
+ else if (nextChar == '>') { putNextCharsInBuffer(1); subElementsProcessed = processElements(TRUE); } //the tag is just closed (maybe some content)
+ else { fprintf(stderr, "processNode : Invalid character '%c'", nextChar); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+
+ //if the code reaches this area, then the processElements has been called and we must
+ //close the opening tag
+ char closeChar = getNextChar();
+ if (closeChar != '<') { fprintf(stderr, "processNode : Invalid character '%c' for closing tag (should be '<')", closeChar); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+
+ do
+ {
+ closeChar = readNextChar();
+ putCharInBuffer(closeChar);
+ }
+ while(closeChar != '>');
+
+ //there is no elements
+ if (subElementsProcessed == 0)
+ {
+ //the node will be stripped
+ if (options->emptyNodeStripping)
+ {
+ xmlPrettyPrintedIndex -= nodeNameLength+4; //because we have '<nodeName ...></nodeName>'
+ resetBackwardIndentation(TRUE);
+
+ if (options->emptyNodeStrippingSpace) { putCharInBuffer(' '); }
+ putCharsInBuffer("/>");
+ }
+ //the closing tag will be put on the same line
+ else if (options->inlineText)
+ {
+ xmlPrettyPrintedIndex -= nodeNameLength+3; //because we have '</nodeName>'
+ resetBackwardIndentation(TRUE);
+
+ //rewrite the node name
+ putCharsInBuffer("</");
+ putCharsInBuffer(currentNodeName);
+ putCharInBuffer('>');
+ }
+ }
+
+ //the node is closed
+ lastNodeOpen = FALSE;
+
+ //freeeeeeee !!!
+ free(nodeName);
+ nodeName = NULL;
+ currentNodeName = NULL;
+}
+
+void processComment()
+{
+ boolean inlineAllowed = FALSE;
+ if (options->inlineComment) { inlineAllowed = isInlineNodeAllowed(); }
+ if (inlineAllowed) { resetBackwardIndentation(TRUE); }
+
+ putNextCharsInBuffer(4); //add the chars '<!--'
+
+ char oldChar = '-';
+ boolean loop = TRUE;
+ while (loop)
+ {
+ char nextChar = readNextChar();
+ if (oldChar == '-' && nextChar == '-') //the comment is being closed
+ {
+ loop = FALSE;
+ }
+
+ if (!isLineBreak(nextChar)) //the comment simply continues
+ {
+ putCharInBuffer(nextChar);
+ oldChar = nextChar;
+ }
+ else if (!options->oneLineComment) //oh ! there is a line break !
+ {
+ readWhites(); //strip the whites and new line
+ putNewLine(); //put a new indentation line
+ oldChar = ' '; //and update the last char
+
+ //TODO manage relative spacing
+ }
+ else //the comments must be inlined
+ {
+ readWhites(); //strip the whites and add a space if necessary
+ if (getPreviousInsertedChar() != ' ') { putCharInBuffer(' '); }
+ }
+ }
+
+ char lastChar = readNextChar(); //should be '>'
+ if (lastChar != '>') { fprintf(stderr, "processComment : last char must be '>' (not '%c')", lastChar); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+ putCharInBuffer(lastChar);
+
+ if (inlineAllowed) { appendIndentation = FALSE; }
+
+ //there vas no node open
+ lastNodeOpen = FALSE;
+}
+
+void processTextNode()
+{
+ //checks if inline is allowed
+ boolean inlineTextAllowed = FALSE;
+ if (options->inlineText) { inlineTextAllowed = isInlineNodeAllowed(); }
+ if (inlineTextAllowed) { resetBackwardIndentation(TRUE); } //remove previous indentation
+
+ //the leading whites are automatically stripped. So we re-add it
+ if (!options->trimLeadingWhites)
+ {
+ int backwardIndex = inputBufferIndex-1;
+ while (inputBuffer[backwardIndex] == ' ' || inputBuffer[backwardIndex] == '\t') { --backwardIndex; } //backward rolling
+
+ //now the input[backwardIndex] IS NOT a white. So we go to the next char...
+ ++backwardIndex;
+
+ //and then re-add the whites
+ while (inputBuffer[backwardIndex] == ' ' || inputBuffer[backwardIndex] == '\t')
+ {
+ putCharInBuffer(inputBuffer[backwardIndex]);
+ ++backwardIndex;
+ }
+ }
+
+ //process the text into the node
+ while(getNextChar() != '<')
+ {
+ char nextChar = readNextChar();
+ if (isLineBreak(nextChar))
+ {
+ readWhites();
+ if (options->oneLineText)
+ {
+ //as we can put text on one line, remove the line break and replace it by a space
+ //but only if the previous char wasn't a space
+ if (getPreviousInsertedChar() != ' ') { putCharInBuffer(' '); }
+ }
+ else
+ {
+ //put a new line only if the closing tag is not reached
+ if (getNextChar() != '<')
+ {
+ putNewLine();
+ }
+ }
+ }
+ else
+ {
+ putCharInBuffer(nextChar);
+ }
+ }
+
+ //strip the trailing whites
+ if (options->trimTrailingWhites)
+ {
+ while(getPreviousInsertedChar() == ' ' || getPreviousInsertedChar() == '\t')
+ {
+ --xmlPrettyPrintedIndex;
+ }
+ }
+
+ //remove the indentation for the closing tag
+ if (inlineTextAllowed) { appendIndentation = FALSE; }
+
+ //there vas no node open
+ lastNodeOpen = FALSE;
+}
+
+void processCDATA()
+{
+ boolean inlineAllowed = FALSE;
+ if (options->inlineCdata) { inlineAllowed = isInlineNodeAllowed(); }
+ if (inlineAllowed) { resetBackwardIndentation(TRUE); }
+
+ putNextCharsInBuffer(9); //putting the '<![CDATA[' into the buffer
+
+ boolean loop = TRUE;
+ char oldChar = '[';
+ while(loop)
+ {
+ char nextChar = readNextChar();
+ if (oldChar == ']' && nextChar == ']') { loop = FALSE; } //end of cdata
+
+ if (!isLineBreak(nextChar)) //the cdata simply continues
+ {
+ putCharInBuffer(nextChar);
+ oldChar = nextChar;
+ }
+ else if (!options->oneLineCdata)
+ {
+ readWhites(); //strip the whites and new line
+ putNewLine(); //put a new indentation line
+ oldChar = ' '; //and update the last char
+
+ //TODO manage relative spacing
+ }
+ else //cdata are inlined
+ {
+ readWhites(); //strip the whites and add a space if necessary
+ if(getPreviousInsertedChar() != ' ') { putCharInBuffer(' '); }
+ }
+ }
+
+ char lastChar = readNextChar(); //should be '>'
+ if (lastChar != '>') { fprintf(stderr, "processCDATA : last char must be '>' (not '%c')", lastChar); printDebugStatus(); result = PRETTY_PRINTING_INVALID_CHAR_ERROR; return; }
+ putCharInBuffer(lastChar);
+
+ if (inlineAllowed) { appendIndentation = FALSE; }
+
+ //there vas no node open
+ lastNodeOpen = FALSE;
+}
+
+void processDoctype()
+{
+ fprintf(stderr, "DOCTYPE is currently not supported by PrettyPrinter\n");
+ fflush(stderr);
+
+ result = PRETTY_PRINTING_NOT_SUPPORTED_YET;
+}
+
+void processDoctypeElement()
+{
+ fprintf(stderr, "ELEMENT is currently not supported by PrettyPrinter\n");
+ fflush(stderr);
+
+ result = PRETTY_PRINTING_NOT_SUPPORTED_YET;
+}
+
+void printDebugStatus()
+{
+ fprintf(stderr, "\n===== INPUT =====\n%s\n=================\ninputLength = %d\ninputIndex = %d\noutputLength = %d\noutputIndex = %d\n",
+ inputBuffer,
+ inputBufferLength,
+ inputBufferIndex,
+ xmlPrettyPrintedLength,
+ xmlPrettyPrintedIndex);
+ fflush(stderr);
+}
Added: trunk/geany-plugins/pretty-printer/src/PrettyPrinter.h
===================================================================
--- trunk/geany-plugins/pretty-printer/src/PrettyPrinter.h (rev 0)
+++ trunk/geany-plugins/pretty-printer/src/PrettyPrinter.h 2009-08-10 10:34:22 UTC (rev 882)
@@ -0,0 +1,55 @@
+/**
+ * Written by Cédric Tabin
+ * http://www.astorm.ch/
+ * Version 1.0 - 08.08.2009
+ *
+ * Code under licence GPLv2
+ * Geany - http://www.geany.org/
+ */
+
+#ifndef PRETTY_PRINTER_H
+#define PRETTY_PRINTER_H
+
+//========================================== INCLUDES ==========================================================
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//========================================== DEFINES ===========================================================
+
+//defines
+#define PRETTY_PRINTING_SUCCESS 0
+#define PRETTY_PRINTING_MALLOC_ERROR -1
+#define PRETTY_PRINTING_INVALID_CHAR_ERROR 1
+#define PRETTY_PRINTING_EMPTY_XML 2
+#define PRETTY_PRINTING_NOT_SUPPORTED_YET 3
+
+//base type
+#define boolean int
+
+//========================================== STRUCTURES =======================================================
+
+typedef struct
+{
+ char indentChar; //char used for indentation
+ int indentLength; //number of char to use for indentation (by default 2 spaces)
+ boolean oneLineText; //text is put on one line
+ boolean inlineText; //if possible text are inline (no return after the opening node and before closing node)
+ boolean oneLineComment; //comments are put on one line
+ boolean inlineComment; //if possible comments are inline (no return after the opening node and before closing node)
+ boolean oneLineCdata; //cdata are put on one line
+ boolean inlineCdata; //if possible cdata are inline (no return after the opening node and before closing node)
+ boolean emptyNodeStripping; //the empty nodes such <node></node> are set to <node/>
+ boolean emptyNodeStrippingSpace; //put a space before the '/>' when a node is stripped
+ boolean forceEmptyNodeSplit; //force an empty node to be splitted : <node /> becomes <node></node> (only if emptyNodeStripping = false)
+ boolean trimLeadingWhites; //trim the leading whites in a text node
+ boolean trimTrailingWhites; //trim the trailing whites in a text node
+} PrettyPrintingOptions;
+
+//========================================== FUNCTIONS =========================================================
+
+int processXMLPrettyPrinting(char** xml, int* length, PrettyPrintingOptions* ppOptions); //process the pretty-printing on a valid xml string (no check done !!!). The ppOptions ARE NOT FREE-ED after processing. The method returns 0 if the pretty-printing has been done.
+PrettyPrintingOptions* createDefaultPrettyPrintingOptions(); //creates a default PrettyPrintingOptions object
+
+#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Plugins-Commits
mailing list