/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/tools/disp/pretty.c,v 1.10 2005/11/05 12:03:15 stefanf Exp $
*/
#include "config.h"
#include "types.h"
#include "ascii.h"
#include "file.h"
#include "pretty.h"
#include "tree.h"
/*
* FORWARD DECLARATIONS
*/
static void display(int);
static void expression(word *, int, int, int, int, int);
/*
* FLAGS SET BY EXTERNAL OPTIONS
*
* Various flags may be given on the command line with affect the form
* of the output. These are documented elsewhere.
*/
BoolT helpflag = TRUE;
BoolT progress = FALSE;
BoolT quickflag = FALSE;
/*
* VARIABLES USED IN PRINTING ROUTINE
*
* The variable maxcol is used to specify the maximum number of columns
* into which the output should be fitted. maxtab gives the current
* indentation. dot_spacing is used to indicate the distance between
* the vertical alignment lines when helpflag is true.
*/
int maxcol = 80;
static int maxtab;
static int dot_spacing;
/*
* CHOICE TABLE
*
* This table is used to decide the maximum suitable indentation. For
* example the entry { a, b, c } means, try printing with an indentation
* of a. If this fits into the required number of columns, try with
* the (larger) indentation c. Otherwise try with the (smaller)
* indentation b.
*/
#define M 100
static int dec [7][3] = {
{ 4, 2, 8 },
{ 2, 1, 3 },
{ 8, 6, M },
{ 1, 0, 1 },
{ 3, 2, 3 },
{ 6, 4, 6 },
{ M, 8, M }
};
/*
* PRINT THE TDF TREE
*
* This routine has overall control of the printing of the tree. It
* determines the most suitable indentation by means of trial runs,
* and then prints the tree with that indentation.
*/
void
pretty_tree(void)
{
int i, j;
int maximum0;
initialize_tree ();
/* Do some trial runs to try to fit into right number of columns... */
printflag = 0;
/* With a maximum indentation of 0... */
maxtab = 0;
display (0);
maximum0 = maximum;
/* Try some larger/smaller values */
if (!quickflag && maximum < maxcol) {
maxtab = 4;
for (i = 0; i < 3; i++) {
display (1);
j = -1;
while (dec[++j][0] != maxtab);
maxtab = dec[j][maximum < maxcol ? 2 : 1];
}
}
/* Work out dot spacing */
dot_spacing = 8;
if (maxtab != 100) dot_spacing = 2 * (maxtab + 1);
if (maxtab == 0) {
if (maximum0 > maxcol) maxcol = maximum0;
dot_spacing = 4;
}
init_spaces (dot_spacing);
/* Actually do the printing */
printflag = 1;
display (0);
if (progress) {
IGNORE fprintf (stderr, "Printed in %d columns.\n", maximum);
}
return;
}
/*
* TRY TO PRETTY-PRINT THE TDF TREE
*
* This routine actually outputs the tree. If test is true, then this
* is only a trial run, and may be aborted if the output exceeds the
* required number of columns.
*/
static void
display(int test)
{
word *ptr;
maximum = 0;
for (ptr = word1.bro; ptr; ptr = ptr->bro) {
column = 0;
expression (ptr, 0, 0, 0, 1, 0);
if (test && (maximum > maxcol)) return;
}
return;
}
/*
* OUTPUT A CHARACTER
*
* This routine outputs a single character into the output file.
*/
#define put_out(c) \
{ \
if (c) { \
if (printflag) IGNORE fputc ((c), pp_file); \
column++; \
lastc = (c); \
} \
}
/*
* OUTPUT A NEWLINE
*
* This routine outputs a newline character into the output file.
* It also causes column to be compared against maximum.
*/
#define new_line() \
{ \
if (column > maximum) maximum = column; \
if (printflag) IGNORE fputc (NEWLINE, pp_file); \
column = 0; \
lastc = NEWLINE; \
}
/*
* OUTPUT A TDF EXPRESSION
*
* This routine is called recursively to print the tree. ptr gives
* the current position within the tree. col gives the column
* where printing should start. flag is true to indicate that a
* newline should be output at the end. pending gives the number
* of trailing close brackets which are pending. first gives a
* character which needs to be output before the current
* expression, and last gives one which should be output after it.
*/
static void
expression(word *ptr, int col, int first, int last, int flag, int pending)
{
word *p;
char bar = '|';
char open = '(';
char close = ')';
char comma = ',';
int more, pends;
char sort, opener, sep;
int len, visible, horiz;
int mflag, new_col, temp_col, temp_max;
/* print initial spaces */
if (column == 0) spaces (col);
/* output first character */
put_out (first);
/* copy out initial text */
col = column;
len = (int) ptr->length;
sort = ptr->type;
if (printflag) IGNORE fputs (ptr->text, pp_file);
column += len;
/* if we have parameters, we need to decode them */
if (sort != SIMPLE) {
/* are the brackets visible or not? */
visible = ((sort == HORIZ_NONE || sort == VERT_NONE) ? 0 : 1);
if (!visible) {
open = close = bar = 0;
comma = ' ';
}
/* are we printing horizontally or vertically? */
horiz = (sort == HORIZ_BRACKETS || sort == HORIZ_NONE);
/* does the maximum tab come into effect? */
mflag = (!horiz && (len > maxtab));
new_col = col + (mflag ? maxtab : len) + 1;
if (sort == VERT_BRACKETS) {
/* try to print things with only one parameter horizontally */
p = ptr->son;
if (p == null) {
horiz = 1;
} else {
if (p->son == null && p->bro == null) horiz = 1;
}
}
/* have a test run, if printing horizontally */
if (horiz && printflag) {
horiz = 1;
/* save old values */
temp_col = column;
temp_max = maximum;
printflag = 0;
maximum = column;
/* open bracket */
put_out (open);
sep = comma;
pends = 0;
/* print parameters */
for (p = ptr->son; p; p = p->bro) {
if (p->bro == null) {
/* for last, take trailing brackets into account */
sep = close;
pends = pending + visible;
}
/* print this parameter */
expression (p, column, 0, sep, 0, pends);
}
/* close bracket */
put_out (last);
/* if this doesn't fit in, try vertically */
if (maximum >= maxcol || column + pending >= maxcol) {
horiz = 0;
mflag = (len > maxtab);
new_col = col + (mflag ? maxtab : len) + 1;
}
/* restore old values */
column = temp_col;
maximum = temp_max;
printflag = 1;
}
if (horiz && printflag) {
/* do horizontal printing of parameters */
/* open bracket */
put_out (open);
sep = comma;
pends = 0;
/* print parameters */
for (p = ptr->son; p; p = p->bro) {
/* for last, take trailing brackets into account */
if (p->bro == null) {
sep = close;
pends = pending + visible;
}
/* print this parameter */
expression (p, column, 0, sep, 0, pends);
}
} else {
/* do vertical printing of parameters */
put_out (open);
opener = bar;
if (mflag) {
new_line ();
spaces (new_col - 1);
}
sep = comma;
more = 1;
pends = 0;
new_col = column;
if (!mflag) {
new_col--;
opener = 0;
}
/* print parameters */
for (p = ptr->son; p; p = p->bro) {
if (p->bro == null) {
/* last requires special treatment */
sep = 0;
more = 0;
pends = pending + visible;
}
/* print this parameter */
expression (p, new_col, opener, sep, more, pends);
opener = bar;
}
if (visible) put_out (close);
}
}
/* output last character */
if (last != ',' || (lastc != '.' && lastc != ':')) put_out (last);
/* and a newline if required */
if (flag) new_line ();
return;
}
syntax highlighted by Code2HTML, v. 0.9.1