diff options
Diffstat (limited to 'src/translators/btparse/tex_tree.c')
-rw-r--r-- | src/translators/btparse/tex_tree.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/src/translators/btparse/tex_tree.c b/src/translators/btparse/tex_tree.c new file mode 100644 index 0000000..0d7d33d --- /dev/null +++ b/src/translators/btparse/tex_tree.c @@ -0,0 +1,414 @@ +/* ------------------------------------------------------------------------ +@NAME : tex_tree.c +@DESCRIPTION: Functions for dealing with strings of TeX code: converting + them to tree representation, traversing the trees to glean + useful information, and converting back to string form. +@GLOBALS : +@CALLS : +@CALLERS : +@CREATED : 1997/05/29, Greg Ward +@MODIFIED : +@VERSION : $Id: tex_tree.c,v 1.4 1999/11/29 01:13:10 greg Rel $ +@COPYRIGHT : Copyright (c) 1996-99 by Gregory P. Ward. All rights reserved. + + This file is part of the btparse library. This library 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. +-------------------------------------------------------------------------- */ + +/*#include "bt_config.h"*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "error.h" +#include "btparse.h" +/*#include "my_dmalloc.h"*/ + +/* blech! temp hack until I make error.c perfect and magical */ +#define string_warning(w) fprintf (stderr, w); + +typedef struct treestack_s +{ + bt_tex_tree * node; + struct treestack_s + * prev, + * next; +} treestack; + + +/* ---------------------------------------------------------------------- + * Stack manipulation functions + */ + +/* ------------------------------------------------------------------------ +@NAME : push_treestack() +@INPUT : *stack + node +@OUTPUT : *stack +@RETURNS : +@DESCRIPTION: Creates and initializes new node in a stack, and pushes it + onto the stack. +@GLOBALS : +@CALLS : +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +push_treestack (treestack **stack, bt_tex_tree *node) +{ + treestack *newtop; + + newtop = (treestack *) malloc (sizeof (treestack)); + newtop->node = node; + newtop->next = NULL; + newtop->prev = *stack; + + if (*stack != NULL) /* stack already has some entries */ + { + (*stack)->next = newtop; + *stack = newtop; + } + + *stack = newtop; + +} /* push_treestack() */ + + +/* ------------------------------------------------------------------------ +@NAME : pop_treestack +@INPUT : *stack +@OUTPUT : *stack +@RETURNS : +@DESCRIPTION: Pops an entry off of a stack of tex_tree nodes, frees up + the wrapper treestack node, and returns the popped tree node. +@GLOBALS : +@CALLS : +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static bt_tex_tree * +pop_treestack (treestack **stack) +{ + treestack * oldtop; + bt_tex_tree * node; + + if (*stack == NULL) + internal_error ("attempt to pop off empty stack"); + oldtop = (*stack)->prev; + node = (*stack)->node; + free (*stack); + if (oldtop != NULL) + oldtop->next = NULL; + *stack = oldtop; + return node; + +} /* pop_treestack() */ + + +/* ---------------------------------------------------------------------- + * Tree creation/destruction functions + */ + +/* ------------------------------------------------------------------------ +@NAME : new_tex_tree +@INPUT : start +@OUTPUT : +@RETURNS : pointer to newly-allocated node +@DESCRIPTION: Allocates and initializes a bt_tex_tree node. +@GLOBALS : +@CALLS : +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static bt_tex_tree * +new_tex_tree (char *start) +{ + bt_tex_tree * node; + + node = (bt_tex_tree *) malloc (sizeof (bt_tex_tree)); + node->start = start; + node->len = 0; + node->child = node->next = NULL; + return node; +} + + +/* ------------------------------------------------------------------------ +@NAME : bt_build_tex_tree +@INPUT : string +@OUTPUT : +@RETURNS : pointer to a complete tree; call bt_free_tex_tree() to free + the entire tree +@DESCRIPTION: Traverses a string looking for TeX groups ({...}), and builds + a tree containing pointers into the string and describing + its brace-structure. +@GLOBALS : +@CALLS : +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +bt_tex_tree * +bt_build_tex_tree (char * string) +{ + int i; + int depth; + int len; + bt_tex_tree + * top, + * cur, + * new; + treestack + * stack; + + i = 0; + depth = 0; + len = strlen (string); + top = new_tex_tree (string); + stack = NULL; + + cur = top; + + while (i < len) + { + switch (string[i]) + { + case '{': /* go one level deeper */ + { + if (i == len-1) /* open brace in last character? */ + { + string_warning ("unbalanced braces: { at end of string"); + goto error; + } + + new = new_tex_tree (string+i+1); + cur->child = new; + push_treestack (&stack, cur); + cur = new; + depth++; + break; + } + case '}': /* pop level(s) off */ + { + while (i < len && string[i] == '}') + { + if (stack == NULL) + { + string_warning ("unbalanced braces: extra }"); + goto error; + } + cur = pop_treestack (&stack); + depth--; + i++; + } + i--; + + if (i == len-1) /* reached end of string? */ + { + if (depth > 0) /* but not at depth 0 */ + { + string_warning ("unbalanced braces: not enough }'s"); + goto error; + } + + /* + * if we get here, do nothing -- we've reached the end of + * the string and are at depth 0, so will just fall out + * of the while loop at the end of this iteration + */ + } + else /* still have characters left */ + { /* to worry about */ + new = new_tex_tree (string+i+1); + cur->next = new; + cur = new; + } + + break; + } + default: + { + cur->len++; + } + + } /* switch */ + + i++; + + } /* while i */ + + if (depth > 0) + { + string_warning ("unbalanced braces (not enough }'s)"); + goto error; + } + + return top; + +error: + bt_free_tex_tree (&top); + return NULL; + +} /* bt_build_tex_tree() */ + + +/* ------------------------------------------------------------------------ +@NAME : bt_free_tex_tree +@INPUT : *top +@OUTPUT : *top (set to NULL after it's free()'d) +@RETURNS : +@DESCRIPTION: Frees up an entire tree created by bt_build_tex_tree(). +@GLOBALS : +@CALLS : itself, free() +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +void +bt_free_tex_tree (bt_tex_tree **top) +{ + if ((*top)->child) bt_free_tex_tree (&(*top)->child); + if ((*top)->next) bt_free_tex_tree (&(*top)->next); + free (*top); + *top = NULL; +} + + + +/* ---------------------------------------------------------------------- + * Tree traversal functions + */ + +/* ------------------------------------------------------------------------ +@NAME : bt_dump_tex_tree +@INPUT : node + depth + stream +@OUTPUT : +@RETURNS : +@DESCRIPTION: Dumps a TeX tree: one node per line, depth indented according + to depth. +@GLOBALS : +@CALLS : itself +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +void +bt_dump_tex_tree (bt_tex_tree *node, int depth, FILE *stream) +{ + char buf[256]; + + if (node == NULL) + return; + + if (node->len > 255) + internal_error ("augughgh! buf too small"); + strncpy (buf, node->start, node->len); + buf[node->len] = (char) 0; + + fprintf (stream, "%*s[%s]\n", depth*2, "", buf); + + bt_dump_tex_tree (node->child, depth+1, stream); + bt_dump_tex_tree (node->next, depth, stream); + +} + + +/* ------------------------------------------------------------------------ +@NAME : count_length +@INPUT : node +@OUTPUT : +@RETURNS : +@DESCRIPTION: Counts the total number of characters that will be needed + to print a string reconstructed from a TeX tree. (Length + of string in each node, plus two [{ and }] for each down + edge.) +@GLOBALS : +@CALLS : itself +@CALLERS : bt_flatten_tex_tree +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static int +count_length (bt_tex_tree *node) +{ + if (node == NULL) return 0; + return + node->len + + (node->child ? 2 : 0) + + count_length (node->child) + + count_length (node->next); +} + + +/* ------------------------------------------------------------------------ +@NAME : flatten_tree +@INPUT : node + *offset +@OUTPUT : *buf + *offset +@RETURNS : +@DESCRIPTION: Dumps a reconstructed string ("flat" representation of the + tree) into a pre-allocated buffer, starting at a specified + offset. +@GLOBALS : +@CALLS : itself +@CALLERS : bt_flatten_tex_tree +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +flatten_tree (bt_tex_tree *node, char *buf, int *offset) +{ + strncpy (buf + *offset, node->start, node->len); + *offset += node->len; + + if (node->child) + { + buf[(*offset)++] = '{'; + flatten_tree (node->child, buf, offset); + buf[(*offset)++] = '}'; + } + + if (node->next) + { + flatten_tree (node->next, buf, offset); + } +} + + +/* ------------------------------------------------------------------------ +@NAME : bt_flatten_tex_tree +@INPUT : top +@OUTPUT : +@RETURNS : flattened string representation of the tree (as a string + allocated with malloc(), so you should free() it when + you're done with it) +@DESCRIPTION: Counts the number of characters needed for a "flat" + string representation of a tree, allocates a string of + that size, and generates the string. +@GLOBALS : +@CALLS : count_length, flatten_tree +@CALLERS : +@CREATED : 1997/05/29, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +char * +bt_flatten_tex_tree (bt_tex_tree *top) +{ + int len; + int offset; + char * buf; + + len = count_length (top); + buf = (char *) malloc (sizeof (char) * (len+1)); + offset = 0; + flatten_tree (top, buf, &offset); + return buf; +} |