Permalink
Browse files

Add custom newline/indent character for PrettyPrint

- Add support for specifying a custom string to use instead of \n as
newline
- Add similar support for a custom string to replace \t for indents
- Add test cases for custom newlines/indents
- Add documentation for custom newlines/indents
  • Loading branch information...
PMLavigne committed Dec 31, 2015
1 parent 89f1ac7 commit 990a97d7a7e0b0eab067814a1f1da507833992b7
Showing with 221 additions and 44 deletions.
  1. +13 −2 README.markdown
  2. +33 −32 src/genx.cc
  3. +1 −1 src/genx.h
  4. +27 −8 src/writer.cc
  5. +1 −1 src/writer.h
  6. +146 −0 test/writer_test.js
View
@@ -145,13 +145,17 @@ writer.startDocument().startElement(elem);
---
#### new Writer([prettyPrint])
#### new Writer([prettyPrint], [newLine], [spacer])
Constructs a new Writer object.
**Arguments**
* prettyPrint (optional, boolean) -- Output human-readable / indented XML.
Defaults to false.
Defaults to `false`
* newLine (optional, String) -- Character(s) to use as the newline character
when prettyPrint is enabled. Defaults to `\n`
* spacer (optional, String) -- Character(s) to use to indent lines when
prettyPrint is enabled. Defaults to `\t`
**Return Value**
@@ -160,7 +164,14 @@ Returns the created Writer
**Example**
```node
// No output formatting
var writer = new genx.Writer();
// PrettyPrint with the default \n newlines and \t to indent
var writer = new genx.Writer(true);
// PrettyPrint with \r\n newlines and four spaces to indent
var writer = new genx.Writer(true, "\r\n", " ");
```
---
View
@@ -15,9 +15,6 @@
#define False 0
#define STRLEN_XMLNS_COLON 6
#define NEWLINE "\n"
#define SPACER "\t"
/*******************************
* writer state
*/
@@ -104,30 +101,32 @@ struct genxAttribute_rec
*/
struct genxWriter_rec
{
FILE * file;
genxSender * sender;
genxStatus status;
writerSequence sequence;
char xmlChars[0x10000];
void * userData;
int nextPrefix;
FILE * file;
genxSender * sender;
genxStatus status;
writerSequence sequence;
char xmlChars[0x10000];
void * userData;
int nextPrefix;
utf8 empty;
Boolean defaultNsDeclared;
genxAttribute xmlnsEquals;
genxElement nowStarting;
plist namespaces;
plist elements;
plist attributes;
plist namespaces;
plist elements;
plist attributes;
plist prefixes;
plist stack;
plist stack;
struct genxAttribute_rec arec;
const char * etext[100];
void * (* alloc)(void * userData, int bytes);
void (* dealloc)(void * userData, void * data);
unsigned int depth;
Boolean shouldNewline;
Boolean prettyPrint;
Boolean firstElementInDocument;
const char * etext[100];
void * (* alloc)(void * userData, int bytes);
void (* dealloc)(void * userData, void * data);
unsigned int depth;
Boolean shouldNewline;
Boolean prettyPrint;
Boolean firstElementInDocument;
constUtf8 newLine;
constUtf8 spacer;
};
/*******************************
@@ -516,7 +515,7 @@ static Boolean isNameChar(genxWriter w, int c)
*/
genxWriter genxNew(void * (* alloc)(void * userData, int bytes),
void (* dealloc)(void * userData, void * data),
void * userData, Boolean prettyPrint)
void * userData, Boolean prettyPrint, constUtf8 newLine, constUtf8 spacer)
{
genxWriter w;
genxNamespace xml;
@@ -596,6 +595,8 @@ genxWriter genxNew(void * (* alloc)(void * userData, int bytes),
w->shouldNewline = 0;
w->firstElementInDocument = 0;
w->prettyPrint = prettyPrint;
w->newLine = newLine;
w->spacer = spacer;
return w;
}
@@ -1173,11 +1174,11 @@ static genxStatus writeStartTag(genxWriter w, bool inlineTag = 0)
}
else
{
SendCheck(w, NEWLINE);
SendCheck(w, w->newLine);
}
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
SendCheck(w, w->spacer);
}
w->depth++;
w->shouldNewline = 0;
@@ -1575,10 +1576,10 @@ genxStatus genxEndElement(genxWriter w)
// We only need to add a newline to closing tags that come right after other closing tags
if(w->shouldNewline)
{
SendCheck(w, NEWLINE);
SendCheck(w, w->newLine);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
SendCheck(w, w->spacer);
}
}
w->shouldNewline = 1;
@@ -1823,10 +1824,10 @@ genxStatus genxAddText(genxWriter w, constUtf8 start)
if(w->prettyPrint && w->shouldNewline)
{
SendCheck(w, NEWLINE);
SendCheck(w, w->newLine);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
SendCheck(w, w->spacer);
}
}
while (*start)
@@ -1967,15 +1968,15 @@ genxStatus genxComment(genxWriter w, constUtf8 text)
}
else if (w->sequence == SEQUENCE_POST_DOC)
if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
if ((w->status = sendx(w, (utf8) w->newLine)) != GENX_SUCCESS)
return w->status;
if(w->prettyPrint && w->shouldNewline)
{
SendCheck(w, NEWLINE);
SendCheck(w, w->newLine);
for(unsigned int tabs = 0; tabs < w->depth; ++tabs)
{
SendCheck(w, SPACER);
SendCheck(w, w->spacer);
}
}
@@ -1987,7 +1988,7 @@ genxStatus genxComment(genxWriter w, constUtf8 text)
return w->status;
if (w->sequence == SEQUENCE_PRE_DOC)
if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
if ((w->status = sendx(w, (utf8) w->newLine)) != GENX_SUCCESS)
return w->status;
return GENX_SUCCESS;
View
@@ -78,7 +78,7 @@ typedef struct genxAttribute_rec * genxAttribute;
*/
genxWriter genxNew(void * (*alloc)(void * userData, int bytes),
void (* dealloc)(void * userData, void * data),
void * userData, int prettyPrint);
void * userData, int prettyPrint, const unsigned char * newLine, const unsigned char * spacer);
/*
* Dispose of a writer, freeing all associated memory
View
@@ -39,6 +39,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "writer.h"
#include "namespace.h"
#define DEFAULT_NEWLINE "\n"
#define DEFAULT_SPACER "\t"
using v8::Function;
using v8::FunctionTemplate;
using v8::Object;
@@ -87,10 +90,10 @@ void Writer::Initialize(Local<Object> exports)
exports->Set(Nan::New("Writer").ToLocalChecked(), tpl->GetFunction());
}
Writer::Writer(const bool prettyPrint)
Writer::Writer(const bool prettyPrint, constUtf8 newLine, constUtf8 spacer)
{
// alloc, free, userData
writer = genxNew(NULL, NULL, this, prettyPrint);
writer = genxNew(NULL, NULL, this, prettyPrint, newLine, spacer);
sender.send = sender_send;
sender.sendBounded = sender_sendBounded;
sender.flush = sender_flush;
@@ -103,20 +106,36 @@ Writer::~Writer()
void Writer::New(const Nan::FunctionCallbackInfo <Value> &args)
{
bool prettyPrint = false;
bool prettyPrint = false;
utf8 newLine = (utf8) DEFAULT_NEWLINE;
utf8 spacer = (utf8) DEFAULT_SPACER;
switch(args.Length()) {
case 0: break;
case 3:
if(!args[2]->IsString()) {
Nan::ThrowTypeError("Third argument to Writer's constructor must be a string");
return;
}
spacer = createUtf8FromString(args[2]->ToString());
case 2:
if(!args[1]->IsString()) {
Nan::ThrowTypeError("Second argument to Writer's constructor must be a string");
return;
}
newLine = createUtf8FromString(args[1]->ToString());
case 1:
if(args[0]->IsBoolean()) {
prettyPrint = args[0]->ToBoolean()->Value();
break;
if(!args[0]->IsBoolean()) {
Nan::ThrowTypeError("First argument to Writer's constructor must be a boolean");
return;
}
prettyPrint = args[0]->ToBoolean()->Value();
break;
default:
Nan::ThrowTypeError("Constructor for Writer expects no arguments, or 1 argument of type Boolean");
Nan::ThrowError("Invalid number of arguments given to Writer's constructor");
return;
}
Writer* writer = new Writer(prettyPrint);
Writer* writer = new Writer(prettyPrint, newLine, spacer);
writer->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
View
@@ -52,7 +52,7 @@ class Writer: public Nan::ObjectWrap
public:
static void Initialize(v8::Local<v8::Object> target);
Writer(const bool prettyPrint);
Writer(const bool prettyPrint, constUtf8 newLine, constUtf8 spacer);
~Writer();
Oops, something went wrong.

0 comments on commit 990a97d

Please sign in to comment.