xmlindent-0.2.17/0000755000175000001440000000000010122527270013536 5ustar pjeusers00000000000000xmlindent-0.2.17/BUGS0000644000175000001440000000047510117320060014217 0ustar pjeusers00000000000000 BUGS The current version has the following known bugs and limitations: - Attributes inside start-tags and empty element tags are not indented. - The scanner trips over on characters that are not part of 7-bit ASCII (ISO-8859-1 and UTF-8, for example, don't work correctly). - Comments are not formatted. xmlindent-0.2.17/ChangeLog0000644000175000001440000001514510122527246015321 0ustar pjeusers000000000000002004-09-17 Pekka Enberg * Release 0.2.17. 2004-09-07 Pekka Enberg * New README file. * Better usage printout. * Support for multiple files in the command line. 2004-03-29 Heikki Orsila * Fixed Makefile dependencies. 2004-03-28 Pekka Enberg * Update BUGS, bump up version, and release 0.2.16. 2004-03-28 Alexander Dupuy * Fixed a bug in line wrapping code that caused corrupted output. 2004-02-16 Pekka Enberg * Released 0.2.15. * Updated BUGS. 2004-02-16 Aubin Paul * Debian packaging. 2004-02-15 Pekka Enberg * Released 0.2.14. * Added a LICENSE file and standard GPL banner to source files. * Added processing instruction parsing (see Section 2.6 of XML 1.0 specification). Thanks to Rob Austein for the bug report. 2004-02-05 Pekka Enberg * Bump up version number and re-release 0.2.13. * Fix for the doctype section parsing fix. Thanks David for testing. * Release 0.2.13 * Fix DOCTYPE parsing error that caused corruption in output file. Bug reported by . 2003-09-28 Pekka Enberg * Release 0.2.12 * Fix empty element indentation. Thanks to Gabriel C Millerd and Mika Viljanen for the bug reports. 2003-09-26 Pekka Enberg * Release 0.2.11 * Fix error in empty element tag indentation that caused corruption in files (spotted by Mika Viljanen). * Avoid zero-length files. Thanks to Mika Viljanen for spotting this one! 2003-09-18 Pekka Enberg * Release 0.2.10 * Code cleanups * Follow indent options for empty element tags too. Thanks to Todd Hammer for pointing out the limitation. 2003-08-09 Pekka Enberg * Release 0.2.9 2003-08-09 Nicola S. Vitale * Parse attributes with character references properly. 2003-07-08 Pekka Enberg * Release 0.2.8 * Minor cleanups to Basile's patch 2003-07-08 Basile Starynkevitch * Fix compile with Flex 2.5.31 2003-07-02 Pekka Enberg * Release 0.2.7 2003-06-11 Nicola S. Vitale * Fix incorrect EOF handling. 2003-06-08 Pekka Enberg * Release 0.2.6 * Add new command line option '-f' (force newline for elements without children) to fix a bug reported by Paul Campbell. 2003-06-04 Pekka Enberg * Release 0.2.5 * Fix bug in parsing attributes scattered across multiple lines. * Fix start-tag attribute parsing bug. 2003-05-14 Pekka Enberg * Fix compile warnings when compiled with '-Wstrict-prototypes' 2003-05-14 Graham Barr * Fix too greedy CDATA section parsing 2003-03-10 Pekka Enberg * Release version 0.2.4 * Cleanups for automatic newline suppressing code. 2003-03-07 Pekka Enberg * Reverse meaning of '-n * Release version 0.2.3 * Fix DOCTYPE parsing error that caused problems with DocBook XMLs. 2003-02-26 Pekka Enberg * Fix EOF check on PPC and probably some other non IA-32 platforms as well 2003-02-25 Pekka Enberg * Makefile fix for Solaris 2003-02-12 Pekka Enberg * Fix bug in line wrapping that ate whitespace from next line. * Add '-nbs' and '-nbe' options. * Release version 0.2.2 * Fix comment parsing bug found by Nicolas Girard. 2003-02-11 Pekka Enberg * Make it compile with non-ANSI C99 compiliant compiler (thanks to Nicolas Girard for spotting this one) 2003-02-08 Pekka Enberg * Release version 0.2.1 * Remove support for forcing newline before tags because it produces too funky results * Support line wrapping command line option '-l' 2003-02-06 Pekka Enberg * Avoid duplicate newlines * Eat whitespace after newline 2003-02-03 Pekka Enberg * Release version 0.2.0 * Support forcing newline after and before start and end-tags. * Use flex for generating the XML parser. Regressions -c not supported anymore. 2002-10-26 Pekka Enberg * Release version 0.1.9 2002-10-25 Pekka Enberg * Emit last line even if there was no newline before end of file. 2002-10-04 Peter Bray * Avoid reallocations for long lines. 2002-10-04 Pekka Enberg * Release version 0.1.8 * Fix segfault for lines longer than 1024 characters. Thanks to Peter Bray for spotting this one. 2002-10-01 Brett Pemberton * RPM spec and Makefile fixes 2002-10-01 Pekka Enberg * Recognize two character end of line markers. * Added overwrite original file command line option -w. 2002-09-29 Pekka Enberg * Release version 0.1.7 2002-09-28 Pekka Enberg * Add RPM spec file. * Add version printing command line option -v. * Add output filename command line option -o. * Fix eats empty lines. * Release version 0.1.6 2002-09-25 Pekka Enberg * Use instead of . * Add compile, install, and uninstall targets to Makefile. 2002-09-24 Thomas Fischer * Add man page. 2002-09-24 Pekka Enberg * Release version 0.1.5 * Leave CDATA sections alone. 2002-09-23 Pekka Enberg * Release version 0.1.4 * Add use tabs command line option. 2002-09-23 Brett Pemberton * Break up xmlindent to xmlindent.c and main.c. * Parse command line arguments with getopts. 2002-09-21 Pekka Enberg * Release version 0.1.3 * Better end of line recognizition. * Add leave comments alone command line option -c. * Recognize start-tags beginning with underscore or colon. 2002-09-21 Markus Hjort * Add indent level command line option -i. 2002-09-19 Pekka Enberg * Release version 0.1.2 * Fix closed XML tag after XML begin tag caused indent errors. * Release version 0.1.1 * Recognize XML comments. * Eat leading whitespace. * Remove fixed-size buffer. Recognize begin tags better. 2002-09-18 Pekka Enberg * Release version 0.1 xmlindent-0.2.17/Makefile0000644000175000001440000000114010117316441015172 0ustar pjeusers00000000000000all: xmlindent PREFIX=/usr/local BIN_INSTALL_DIR=$(PREFIX)/bin MAN_INSTALL_DIR=$(PREFIX)/share/man/man1 xmlindent: indent.c buffer.c main.c gcc -Wall -g error.c indent.c buffer.c main.c -o xmlindent -lfl indent.c: lex.yy.c lex.yy.c: xmlindent.yy flex xmlindent.yy install: xmlindent mkdir -p $(BIN_INSTALL_DIR) mkdir -p $(MAN_INSTALL_DIR) install -m555 xmlindent $(BIN_INSTALL_DIR)/xmlindent install -m444 xmlindent.1 $(MAN_INSTALL_DIR)/xmlindent.1 uninstall: rm -f $(BIN_INSTALL_DIR)/xmlindent rm -f $(MAN_INSTALL_DIR)/xmlindent.1 clean: rm -f xmlindent *.o core lex.yy.c .PHONY: all clean xmlindent-0.2.17/buffer.c0000644000175000001440000000602610100020524015141 0ustar pjeusers00000000000000/* * Copyright (C) 2002 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "error.h" #include "buffer.h" /* Initialize buffer. */ void buffer_init(struct buffer * buffer, size_t initial_capacity) { buffer->data = malloc(initial_capacity * sizeof(unsigned char)); buffer->length = 0; buffer->capacity = initial_capacity; } /* Release buffer. */ void buffer_release(struct buffer * buffer) { if (buffer->capacity > 0) { free(buffer->data); buffer->data = NULL; buffer->capacity = 0; } buffer->length = 0; } /* Check if buffer is full. */ bool buffer_is_full(struct buffer * buffer) { return (buffer->capacity == buffer->length); } #define BUFFER_GROWTH_INCREMENT 256 /* Grow buffer by one. */ void buffer_grow(struct buffer * buffer) { buffer->data = realloc(buffer->data, (buffer->capacity + BUFFER_GROWTH_INCREMENT) * sizeof(unsigned char)); if (buffer->data == NULL) { error("Could not allocate memory for buffer."); exit(1); } buffer->capacity += BUFFER_GROWTH_INCREMENT; } /* Push character at the end of buffer. */ void buffer_push_char(struct buffer * buffer, int c) { if (buffer_is_full(buffer)) { buffer_grow(buffer); } buffer->data[buffer->length] = c; buffer->length++; } /* Push string at the end of buffer. */ void buffer_push_str(struct buffer * buffer, const char * text) { int i; for (i = 0; i < strlen(text); i++) { buffer_push_char(buffer, (int) text[i]); } } /* Pop item from back of buffer. */ int buffer_pop_char(struct buffer * buffer) { int result = -1; if (buffer->length > 0) { buffer->length--; result = buffer->data[buffer->length]; } else { error("Buffer underflow."); } return result; } /* Flush buffer to output stream. */ void buffer_flush(struct buffer * buffer, FILE * output) { int i; for (i = 0; i < buffer->length; i++) { fputc(buffer->data[i], output); } buffer->length = 0; } /* Return buffer size. */ size_t buffer_size(struct buffer * buffer) { return buffer->length; } void buffer_copy(struct buffer * dest, struct buffer * src) { int i; for (i = 0; i < src->length; i++) { buffer_push_char(dest, src->data[i]); } } void buffer_clear(struct buffer * buf) { buf->length = 0; } xmlindent-0.2.17/buffer.h0000644000175000001440000000271110100020524015143 0ustar pjeusers00000000000000/* * Copyright (C) 2002 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _BUFFER_H_ #define _BUFFER_H_ 1 #include #include #include /* Buffer used to hold XML stream. */ struct buffer { char * data; size_t length; size_t capacity; }; void buffer_init(struct buffer * buffer, size_t initial_capacity); void buffer_release(struct buffer * buffer); void buffer_push_str(struct buffer * buffer, const char * text); void buffer_push_char(struct buffer * buffer, int c); int buffer_pop_char(struct buffer * buffer); void buffer_flush(struct buffer * buffer, FILE * output); void buffer_copy(struct buffer * dest, struct buffer * src); void buffer_clear(struct buffer * buf); size_t buffer_size(struct buffer * buffer); #endif xmlindent-0.2.17/error.c0000644000175000001440000000202510100020524015014 0ustar pjeusers00000000000000/* * Copyright (C) 2002 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include /* Print error message. */ void error(const char * format, ...) { va_list args; fprintf(stderr, "Error: "); va_start(args, format); vfprintf(stderr, format, args); va_end(args); fputc('\n', stderr); } xmlindent-0.2.17/error.h0000644000175000001440000000157110100020524015026 0ustar pjeusers00000000000000/* * Copyright (C) 2002 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _ERROR_H_ #define _ERROR_H_ 1 /* Print error message. */ void error(const char * format, ...); #endif xmlindent-0.2.17/indent.c0000644000175000001440000002747110100020524015160 0ustar pjeusers00000000000000/* * Copyright (C) 2002-2004 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "buffer.h" #include "indent.h" /* * Functions the generated scanner uses. */ static void xml_declaration(void); static void cdata_section(void); static void doctype_declaration(void); static void start_tag(void); static void end_tag(void); static void empty_element_tag(void); static void comment(void); static void content(void); static void processing_insn(void); static void do_newline(struct buffer * buffer, const char * text); #include "lex.yy.c" /* * Flex unput() wrapper */ extern void do_unput(int); /* * Functions we use. */ static void newline(void); /* * We have three buffers: primary, secondary, and tag buffer. The first one * has all data before previous start-tag, second one has data encountered * after previous start-tag, and the last one _has_ the start-tag. */ struct buffer primary_buf; struct buffer secondary_buf; struct buffer tag_buf; struct buffer * current_buf; /* * Indent options. To be modified only trough set_options. */ static char indent_char; static int num_indent_chars; static bool force_newline_after_start_tag; static bool force_newline_after_end_tag; static bool force_newline_before_start_tag; static bool force_newline_before_end_tag; static bool force_always; static int max_columns; static bool wrap_long_lines; static FILE * indent_output; /* * Default options. */ #define DEFAULT_INDENT_CHAR ' ' #define DEFAULT_NUM_INDENT_CHARS 4 /* Set default indent options. */ void indent_options_set_defaults(struct indent_options * opts) { opts->indent_char = DEFAULT_INDENT_CHAR; opts->num_indent_chars = DEFAULT_NUM_INDENT_CHARS; opts->max_columns = -1; opts->wrap_long_lines = false; opts->force_newline_after_start_tag = true; opts->force_newline_after_end_tag = true; opts->force_newline_before_start_tag = true; opts->force_newline_before_end_tag = true; opts->force_always = false; } /* Set indent options. */ static void set_options(struct indent_options * opts) { indent_char = opts->indent_char; num_indent_chars = opts->num_indent_chars; max_columns = opts->max_columns; wrap_long_lines = opts->wrap_long_lines; force_newline_after_start_tag = opts->force_newline_after_start_tag; force_newline_after_end_tag = opts->force_newline_after_end_tag; force_newline_before_start_tag = opts->force_newline_before_start_tag; force_newline_before_end_tag = opts->force_newline_before_end_tag; force_always = opts->force_always; } #define BUFFER_INITIAL_CAPACITY 1024 void indent(FILE * input, FILE * output, struct indent_options * opts) { set_options(opts); buffer_init(&primary_buf, BUFFER_INITIAL_CAPACITY); buffer_init(&secondary_buf, BUFFER_INITIAL_CAPACITY); buffer_init(&tag_buf, BUFFER_INITIAL_CAPACITY); current_buf = &primary_buf; yyin = input; indent_output = output; yylex(); /* * There might not have been a newline before EOF. */ buffer_flush(current_buf, indent_output); buffer_release(&primary_buf); buffer_release(&secondary_buf); buffer_release(&tag_buf); } /* Print indent characters. */ static void print_indent(FILE * output, int indent_level) { int i; for (i = 0; i < (num_indent_chars * indent_level); i++) { fputc(indent_char, output); } } static void xml_declaration(void) { buffer_push_str(current_buf, yytext); } static void cdata_section(void) { buffer_push_str(current_buf, yytext); } static void doctype_declaration(void) { buffer_push_str(current_buf, yytext); } /* XML end of line characters. */ #define CARRIAGE_RETURN 0x0D #define LINE_FEED 0x0A #define NEL 0x85 static inline bool is_newline(int current) { if ((CARRIAGE_RETURN == current) || (LINE_FEED == current) || (NEL == current)) return true; return false; } /* Check for whitespace character. */ static inline bool is_whitespace(int c) { return ((c == ' ') || (c == '\f') || (c == '\t') || (c == '\v')); } /* Eat whitespace from stream. */ static void eat_whitespace(void) { for (;;) { int current = input(); if (!is_whitespace(current)) { do_unput(current); break; } } } static int indent_level = 0; static int indent_delta = 0; /* Force newline before tag. Use buffer for getting current character. */ static void force_newline_before_tag(struct buffer * buffer) { int current; if (buffer_size(buffer) == 0) { /* * We just did a newline, no need to force it. */ return; } current = buffer_pop_char(buffer); buffer_push_char(buffer, current); if (!is_newline(current)) { do_newline(buffer, "\n"); eat_whitespace(); } } /* Force newline after tag. Use lexer to get current character. */ static void force_newline_after_tag(struct buffer * buffer) { int current = input(); if (!is_newline(current)) { do_newline(buffer, "\n"); eat_whitespace(); } do_unput(current); } static bool using_primary_buf(void) { return current_buf == &primary_buf; } /* Merge tag and secondary buffer to primary buffer. Force newlines if necessary. This routine is used with start-tags. */ static void merge_buffers_start_tag(void) { if (force_newline_before_start_tag) { force_newline_before_tag(&primary_buf); } buffer_copy(&primary_buf, &tag_buf); indent_delta++; if (force_newline_after_start_tag) { force_newline_after_tag(&primary_buf); } buffer_copy(&primary_buf, &secondary_buf); buffer_clear(&tag_buf); buffer_clear(&secondary_buf); current_buf = &primary_buf; } /* Merge tag and secondary buffer back to primary buffer. */ static void merge_buffers(void) { buffer_copy(&primary_buf, &tag_buf); buffer_copy(&primary_buf, &secondary_buf); buffer_clear(&tag_buf); buffer_clear(&secondary_buf); current_buf = &primary_buf; /* We just processed a start-tag so bump up indent_delta. */ indent_delta++; } /* Force newline for wrapping line. Use lexer to get current character and do not eat whitespace from next line. */ static void force_newline_for_wrap(struct buffer * buffer) { int current = input(); /* * Flush all pending stuff before doing the newline. */ if (!using_primary_buf()) { merge_buffers(); } do_newline(current_buf, "\n"); if (!is_newline(current)) do_unput(current); } static void start_tag(void) { char * tmp; /* * Save text because merge_buffers_start_tag may trash it. */ tmp = strdup(yytext); if (!using_primary_buf()) { /* * This is second start-tag. Thus first one has children. We can force * newline here if we want. */ merge_buffers_start_tag(); } buffer_push_str(&tag_buf, tmp); current_buf = &secondary_buf; free(tmp); } static void end_tag(void) { bool can_force_newline; char * tmp; /* * Save text because force_newline_before_tag can trash it. */ tmp = strdup(yytext); if (using_primary_buf()) { can_force_newline = true; } else { /* The element didn't have any children - force newline only if user explicity requested that. */ merge_buffers(); can_force_newline = force_always; } if (force_newline_before_end_tag && can_force_newline) { force_newline_before_tag(current_buf); } buffer_push_str(current_buf, tmp); indent_delta--; if (force_newline_after_end_tag && can_force_newline) { force_newline_after_tag(current_buf); } free(tmp); } static void empty_element_tag(void) { bool can_force_newline; char * tmp; /* * Save text because force_newline_before_tag can trash it. */ tmp = strdup(yytext); /* We treat empty element tag as a "merged" start-tag and end-tag. Therefore we use start-tag options before the tag and end-tag options after the tag. */ if (!using_primary_buf()) { /* * This is second start-tag. Thus first one has children. We can force * newline here if we want. */ merge_buffers_start_tag(); can_force_newline = force_always; } else { can_force_newline = true; } buffer_push_str(current_buf, tmp); if (force_newline_after_end_tag && can_force_newline) { /* Empty element never has any children. Force newline only if user explicitly requested it. */ force_newline_after_tag(current_buf); } free(tmp); } static int input_and_push(void) { int ret = input(); if (ret != EOF) buffer_push_char(current_buf, ret); return ret; } static void comment(void) { int c; buffer_push_str(current_buf, yytext); for (;;) { while ((c = input_and_push()) != '-' && c != EOF) ; if ((c = input_and_push()) != '-') { continue; } if ((c = input_and_push()) == '>') { break; } } } static void do_newline(struct buffer * buffer, const char * text) { buffer_push_str(buffer, text); if (indent_delta < 0) indent_level += indent_delta; print_indent(indent_output, indent_level); if (indent_delta > 0) indent_level += indent_delta; indent_delta = 0; buffer_flush(buffer, indent_output); } static void newline(void) { /* * Flush all pending stuff before doing the newline. */ if (!using_primary_buf()) { merge_buffers(); } do_newline(current_buf, "\n"); eat_whitespace(); } /* * We assume tab is equal to 8 spaces. */ #define TAB_SIZE 8 static unsigned long indent_size(void) { return (indent_char == '\t' ? indent_level * TAB_SIZE : indent_level * num_indent_chars); } static bool need_wrap(struct buffer * buffer) { if (buffer == &primary_buf) return buffer_size(buffer) + indent_size() == max_columns; else return (buffer_size(&primary_buf) + buffer_size(&tag_buf) + buffer_size(buffer) + indent_size()) >= max_columns; } static void content(void) { char current; /* * We should get one character at a time. */ assert(strlen(yytext) == 1); current = yytext[0]; if (current == EOF) return; if (is_newline(current)) { newline(); return; } buffer_push_char(current_buf, current); /* * Forcing newline changes 'text' so lets do it after we've pushed * it to the buffer. */ if (wrap_long_lines && need_wrap(current_buf)) { struct buffer tmp; buffer_init(&tmp, buffer_size(current_buf)); /* * Find last character that was not whitespace */ for (;;) { int c; if (buffer_size(current_buf) == 0) break; c = buffer_pop_char(current_buf); if (is_whitespace(c)) { /* * Do not push whitespace because it would appear * after the newline. */ break; } /* * Characters are put in tmp buffer in reverse order. */ buffer_push_char(&tmp, c); } force_newline_for_wrap(current_buf); /* * Restore non-wrapped text into buffer. */ while (buffer_size(&tmp) > 0) { buffer_push_char(current_buf, buffer_pop_char(&tmp)); } buffer_release(&tmp); } } static void processing_insn(void) { buffer_push_str(current_buf, yytext); } xmlindent-0.2.17/indent.h0000644000175000001440000000247310100020524015160 0ustar pjeusers00000000000000/* * Copyright (C) 2002-2003 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _INDENT_H_ #define _INDENT_H_ 1 #include "buffer.h" #include /* * Indent options */ struct indent_options { char indent_char; int num_indent_chars; bool force_newline_after_start_tag; bool force_newline_after_end_tag; bool force_newline_before_start_tag; bool force_newline_before_end_tag; bool force_always; int max_columns; bool wrap_long_lines; }; void indent_options_set_defaults(struct indent_options * opts); void indent(FILE * input, FILE * output, struct indent_options * opts); #endif xmlindent-0.2.17/main.c0000644000175000001440000001211210117317572014631 0ustar pjeusers00000000000000/* * Copyright (C) 2002-2004 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "buffer.h" #include "error.h" #include "indent.h" #include "version.h" #include #include #include #include #include #include static void version(void) { printf("XML Indent, version %s\n", VERSION); printf("Copyright (C) 2002-2004 Pekka Enberg\n"); } static void usage(void) { printf("Usage: %s [options] [filename] ...\n", PACKAGE); printf("Options:\n"); printf("\t-o \tOutput file\n"); printf("\t-i \tIndent level\n"); printf("\t-t\t\tUse tabs instead of spaces for indent\n"); printf("\t-l \tMaximum columns for line wrapping\n"); printf("\t-n \tSuppress newline at position\n"); printf("\t-f\t\tForce newline on elements without children\n"); printf("\t-h\t\tHelp\n"); printf("\t-v\t\tVersion information\n"); printf("\t-w\t\tOverwrite original file\n"); } /* Overwrite original files. */ static bool overwrite = false; static int format_file(const char * filename, char * output_filename, struct indent_options * opts) { char input_filename[FILENAME_MAX]; FILE * input; FILE * output; input_filename[0] = '\0'; if (filename != NULL) { strcpy(input_filename, filename); /* Avoid zero-length files. */ if (overwrite || strcmp(input_filename, output_filename) == 0) { char backup_filename[FILENAME_MAX]; strcpy(backup_filename, input_filename); strcat(backup_filename, "~"); rename(input_filename, backup_filename); strcpy(output_filename, input_filename); strcpy(input_filename, backup_filename); } } if (strlen(input_filename) > 0) { input = fopen(input_filename, "r"); if (NULL == input) { error("Could not open '%s': %s.", input_filename, strerror(errno)); return EXIT_FAILURE; } } else { input = stdin; } if (strlen(output_filename) > 0) { output = fopen(output_filename, "w"); if (NULL == output) { error("Could not open '%s': %s.", output_filename, strerror(errno)); return EXIT_FAILURE; } } else { output = stdout; } indent(input, output, opts); if (output != stdout) fclose(output); if (input != stdout) fclose(input); return EXIT_SUCCESS; } static void parse_force_newline_arg(char * arg, struct indent_options * opts) { if (strcmp(arg, "as") == 0) { opts->force_newline_after_start_tag = false; } else if (strcmp(arg, "ae") == 0) { opts->force_newline_after_end_tag = false; } else if (strcmp(arg, "bs") == 0) { opts->force_newline_before_start_tag = false; } else if (strcmp(arg, "be") == 0) { opts->force_newline_before_end_tag = false; } } static void parse_args(int argc, char * argv[], struct indent_options * opts, char * output_filename) { bool explicit_indent_level = false; for (;;) { int arg_index = getopt(argc, argv, "hfi:l:o:n:tvw"); if (arg_index == -1) { break; } switch (arg_index) { case 'h': usage(); exit(EXIT_SUCCESS); case 'i': opts->num_indent_chars = atoi(optarg); explicit_indent_level = true; break; case 'l': opts->max_columns = atoi(optarg); opts->wrap_long_lines = true; break; case 't': opts->indent_char = '\t'; if (!explicit_indent_level) { /* Default indent level for tabs is different. */ opts->num_indent_chars = 1; } break; case 'f': opts->force_always = true; break; case 'o': strcpy(output_filename, optarg); break; case 'n': parse_force_newline_arg(optarg, opts); break; case 'v': version(); exit(EXIT_SUCCESS); case 'w': overwrite = true; break; default: usage(); exit(EXIT_FAILURE); } } } int main(int argc, char * argv[]) { char output_filename[FILENAME_MAX]; struct indent_options opts; int ret = EXIT_SUCCESS; int i; output_filename[0] = '\0'; indent_options_set_defaults(&opts); parse_args(argc, argv, &opts, output_filename); /* Iterate over all input files. */ for (i = optind; i < argc; i++) { ret = format_file(argv[i], output_filename, &opts); if (ret != EXIT_SUCCESS) break; } /* When we have no input files to process, wait for stdin. */ if (optind == argc) ret = format_file(NULL, output_filename, &opts); return ret; } xmlindent-0.2.17/test.xml0000644000175000001440000000101510100020524015216 0ustar pjeusers00000000000000 <_root> <:node>

we don't want to force newline here

but in here, do want that

This line is clearly too long for 80-column terminal. Perhaps it should be wrapped? xmlindent-0.2.17/version.h0000644000175000001440000000156410100020525015365 0ustar pjeusers00000000000000/* * Copyright (C) 2002-2004 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _VERSION_H #define _VERSION_H 1 #define PACKAGE "xmlindent" #define VERSION "0.2.17" #endif xmlindent-0.2.17/xmlindent.10000644000175000001440000000230710100020525015607 0ustar pjeusers00000000000000.TH "xmlindent" "1" "0.2.17" "Thomas Fischer" "" .SH "NAME" .LP xmlindent \- XML stream reformatter .SH "SYNTAX" .LP xmlindent [\fB\-o\fP \fIoutput file\fP] [\fB\-i\fP \fIindent level\fP] [\fB\-l\fP \fImax columns\fP] [\fB\-n\fP \fInewline position\fP] [\fB\-t\fP] [\fB\-c\fP] [\fB-f\fP] [\fB\-w\fP] [\fB\-h\fP] [\fB\-v\fP] .SH "DESCRIPTION" .LP XML Indent is a XML stream reformatter written in ANSI C. It is analogous to GNU indent. .SH "OPTIONS" .LP .TP \fB\-o\fR \fIoutput file\fP Write indented XML to \fIoutput file\fP .TP \fB\-i\fR \fIindent level\fP Indent each level \fIindent level\fP spaces deeper .TP \fB\-l\fR \fImax columns\fP Wrap lines longer than \fImax columns\fP .TP \fB\-t\fR Use tabs instead of spaces .TP \fB\-nas\fR Suppress newline after start-tag .TP \fB\-nae\fR Suppress newline after end-tag .TP \fB\-nbs\fR Suppress newline before start-tag .TP \fB\-nbe\fR Suppress newline before end-tag .TP \fB\-f\fR Force newline on elements without children .TP \fB\-w\fR Overwrite original file .TP \fB\-v\fR Show version .TP \fB\-h\fR Show command line help .SH "AUTHORS" .LP Pekka Enberg .br Thomas Fischer (man page) .SH "SEE ALSO" .LP indent(1) xmlindent-0.2.17/xmlindent.spec0000644000175000001440000000132210100020525016375 0ustar pjeusers00000000000000%define version 0.2.17 %define release 1 %define name xmlindent Summary: a XML stream reformatter Name: %{name} Version: %{version} Release: %{release} Copyright: GPL Group: Text Processing/Markup/XML Source: http://www.cs.helsinki.fi/u/~penberg/xmlindent/src/xmlindent-%{version}.tar.gz URL: http://www.cs.helsinki.fi/u/~penberg/xmlindent/ BuildRoot: /var/tmp/%{name}-%{version} Packager: Pekka Enberg %description XML Indent is a XML stream reformatter written in ANSI C. It is analogous to GNU indent. %prep %setup %build make all %install rm -rf $RPM_BUILD_ROOT make PREFIX="$RPM_BUILD_ROOT/usr" install %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/* %{_mandir}/*/* xmlindent-0.2.17/xmlindent.yy0000644000175000001440000000500110100020525016102 0ustar pjeusers00000000000000/* * Copyright (C) 2002-2004 Pekka Enberg * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Scanner for XML Indent. */ %{ /* Flex 2.5.31 and higher limits use of unput() to definitions section of the input file. */ static void yyunput(int, char *); void do_unput(int c) { unput(c); } %} /* * We're mostly following the XML 1.0 specification: * http://www.w3.org/TR/2000/REC-xml-20001006 */ LETTER [[:alpha:]] DIGIT [[:digit:]] NAME_CHAR ({LETTER}|{DIGIT}|\.|-|_|:) NAME ({LETTER}|_|:)({NAME_CHAR})* SPACE [ \t\r\n]+ QUOTED_LITERAL (\"[^\"]*\")|(\'[^\']*\') SYSTEM_LITERAL {QUOTED_LITERAL} PUBID_LITERAL {QUOTED_LITERAL} EXTERNAL_ID ("SYSTEM"{SPACE}{SYSTEM_LITERAL}|"PUBLIC"{SPACE}{PUBID_LITERAL}{SPACE}{SYSTEM_LITERAL}) XML_DECLARATION "" DOCTYPE_DECLARATION "])*"]")?{SPACE}*">" CDATA_SECTION "])*"]]>" PROCESSING_INSN "" ENTITY_REF (\&{NAME};) CHAR_REF ((\&#[0-9]+;)|(\&#x[0-9a-fA-F]+;)) REFERENCE ({ENTITY_REF}|{CHAR_REF}) ATT_VALUE ((\"([^<\&\"]|{REFERENCE})*\")|(\'([^<\&\']|{REFERENCE})*\')) ATTRIBUTE {NAME}{SPACE}*"="{SPACE}*{ATT_VALUE} START_TAG "<"{NAME}({SPACE}*{ATTRIBUTE})*{SPACE}*">" END_TAG "" EMPTY_ELEMENT_TAG "<"{NAME}({SPACE}*{ATTRIBUTE})*{SPACE}*"/>" CONTENT [^\<] COMMENT "