File indexing completed on 2025-01-26 04:44:01

0001 /* ------------------------------------------------------------------------
0002 @NAME       : tex_tree.c
0003 @DESCRIPTION: Functions for dealing with strings of TeX code: converting
0004               them to tree representation, traversing the trees to glean
0005               useful information, and converting back to string form.
0006 @GLOBALS    : 
0007 @CALLS      : 
0008 @CALLERS    : 
0009 @CREATED    : 1997/05/29, Greg Ward
0010 @MODIFIED   : 
0011 @VERSION    : $Id: tex_tree.c,v 1.4 1999/11/29 01:13:10 greg Rel $
0012 @COPYRIGHT  : Copyright (c) 1996-99 by Gregory P. Ward.  All rights reserved.
0013 
0014               This file is part of the btparse library.  This library is
0015               free software; you can redistribute it and/or modify it under
0016               the terms of the GNU General Public License as
0017               published by the Free Software Foundation; either version 2
0018               of the License, or (at your option) any later version.
0019 -------------------------------------------------------------------------- */
0020 
0021 /*#include "bt_config.h"*/
0022 #include <stdlib.h>
0023 #include <stdio.h>
0024 #include <string.h>
0025 #include "error.h"
0026 #include "btparse.h"
0027 /*#include "my_dmalloc.h"*/
0028 
0029 /* blech! temp hack until I make error.c perfect and magical */
0030 #define string_warning(w) fprintf (stderr, w);
0031 
0032 typedef struct treestack_s
0033 {
0034    bt_tex_tree * node;
0035    struct treestack_s
0036                * prev,
0037                * next;
0038 } treestack;
0039 
0040 
0041 /* ----------------------------------------------------------------------
0042  * Stack manipulation functions
0043  */
0044 
0045 /* ------------------------------------------------------------------------
0046 @NAME       : push_treestack()
0047 @INPUT      : *stack
0048               node
0049 @OUTPUT     : *stack
0050 @RETURNS    : 
0051 @DESCRIPTION: Creates and initializes new node in a stack, and pushes it
0052               onto the stack.
0053 @GLOBALS    : 
0054 @CALLS      : 
0055 @CALLERS    : 
0056 @CREATED    : 1997/05/29, GPW
0057 @MODIFIED   : 
0058 -------------------------------------------------------------------------- */
0059 static void
0060 push_treestack (treestack **stack, bt_tex_tree *node)
0061 {
0062    treestack  *newtop;
0063 
0064    newtop = (treestack *) malloc (sizeof (treestack));
0065    newtop->node = node;
0066    newtop->next = NULL;
0067    newtop->prev = *stack;
0068 
0069    if (*stack != NULL)                  /* stack already has some entries */
0070    {
0071       (*stack)->next = newtop;
0072       *stack = newtop;
0073    }
0074 
0075    *stack = newtop;
0076 
0077 } /* push_treestack() */
0078 
0079 
0080 /* ------------------------------------------------------------------------
0081 @NAME       : pop_treestack
0082 @INPUT      : *stack
0083 @OUTPUT     : *stack
0084 @RETURNS    : 
0085 @DESCRIPTION: Pops an entry off of a stack of tex_tree nodes, frees up
0086               the wrapper treestack node, and returns the popped tree node.
0087 @GLOBALS    : 
0088 @CALLS      : 
0089 @CALLERS    : 
0090 @CREATED    : 1997/05/29, GPW
0091 @MODIFIED   : 
0092 -------------------------------------------------------------------------- */
0093 static bt_tex_tree *
0094 pop_treestack (treestack **stack)
0095 {
0096    treestack *   oldtop;
0097    bt_tex_tree * node;
0098 
0099    if (*stack == NULL)
0100       internal_error ("attempt to pop off empty stack");
0101    oldtop = (*stack)->prev;
0102    node = (*stack)->node;
0103    free (*stack);
0104    if (oldtop != NULL)
0105       oldtop->next = NULL;
0106    *stack = oldtop;
0107    return node;
0108 
0109 } /* pop_treestack() */
0110 
0111 
0112 /* ----------------------------------------------------------------------
0113  * Tree creation/destruction functions
0114  */
0115 
0116 /* ------------------------------------------------------------------------
0117 @NAME       : new_tex_tree
0118 @INPUT      : start
0119 @OUTPUT     : 
0120 @RETURNS    : pointer to newly-allocated node
0121 @DESCRIPTION: Allocates and initializes a bt_tex_tree node.
0122 @GLOBALS    : 
0123 @CALLS      : 
0124 @CALLERS    : 
0125 @CREATED    : 1997/05/29, GPW
0126 @MODIFIED   : 
0127 -------------------------------------------------------------------------- */
0128 static bt_tex_tree *
0129 new_tex_tree (char *start)
0130 {
0131    bt_tex_tree * node;
0132 
0133    node = (bt_tex_tree *) malloc (sizeof (bt_tex_tree));
0134    node->start = start;
0135    node->len = 0;
0136    node->child = node->next = NULL;
0137    return node;
0138 }
0139 
0140 
0141 /* ------------------------------------------------------------------------
0142 @NAME       : bt_build_tex_tree
0143 @INPUT      : string
0144 @OUTPUT     : 
0145 @RETURNS    : pointer to a complete tree; call bt_free_tex_tree() to free
0146               the entire tree
0147 @DESCRIPTION: Traverses a string looking for TeX groups ({...}), and builds
0148               a tree containing pointers into the string and describing
0149               its brace-structure.
0150 @GLOBALS    : 
0151 @CALLS      : 
0152 @CALLERS    : 
0153 @CREATED    : 1997/05/29, GPW
0154 @MODIFIED   : 
0155 -------------------------------------------------------------------------- */
0156 bt_tex_tree *
0157 bt_build_tex_tree (char * string)
0158 {
0159    int     i;
0160    int     depth;
0161    int     len;
0162    bt_tex_tree
0163          * top,
0164          * cur,
0165          * new;
0166    treestack
0167          * stack;
0168 
0169    i = 0;
0170    depth = 0;
0171    len = strlen (string);
0172    top = new_tex_tree (string);
0173    stack = NULL;
0174 
0175    cur = top;
0176    
0177    while (i < len)
0178    {
0179       switch (string[i])
0180       {
0181          case '{':                      /* go one level deeper */
0182          {
0183             if (i == len-1)             /* open brace in last character? */
0184             {
0185                string_warning ("unbalanced braces: { at end of string");
0186                goto error;
0187             }
0188 
0189             new = new_tex_tree (string+i+1);
0190             cur->child = new;
0191             push_treestack (&stack, cur);
0192             cur = new;
0193             depth++;
0194             break;
0195          }
0196          case '}':                      /* pop level(s) off */
0197          {
0198             while (i < len && string[i] == '}')
0199             {
0200                if (stack == NULL)
0201                {
0202                   string_warning ("unbalanced braces: extra }");
0203                   goto error;
0204                }
0205                cur = pop_treestack (&stack);
0206                depth--;
0207                i++;
0208             }
0209             i--;
0210 
0211             if (i == len-1)             /* reached end of string? */
0212             {
0213                if (depth > 0)           /* but not at depth 0 */
0214                {
0215                   string_warning ("unbalanced braces: not enough }'s");
0216                   goto error;
0217                }
0218 
0219                /* 
0220                 * if we get here, do nothing -- we've reached the end of 
0221                 * the string and are at depth 0, so will just fall out
0222                 * of the while loop at the end of this iteration
0223                 */
0224             }
0225             else                        /* still have characters left */
0226             {                           /* to worry about */
0227                new = new_tex_tree (string+i+1);
0228                cur->next = new;
0229                cur = new;
0230             }
0231 
0232             break;
0233          }
0234          default:
0235          {
0236             cur->len++;
0237          }
0238 
0239       } /* switch */
0240 
0241       i++;
0242 
0243    } /* while i */
0244 
0245    if (depth > 0)
0246    {
0247       string_warning ("unbalanced braces (not enough }'s)");
0248       goto error;
0249    }
0250 
0251    return top;
0252 
0253 error:
0254    bt_free_tex_tree (&top);
0255    return NULL;
0256 
0257 } /* bt_build_tex_tree() */
0258 
0259 
0260 /* ------------------------------------------------------------------------
0261 @NAME       : bt_free_tex_tree
0262 @INPUT      : *top
0263 @OUTPUT     : *top (set to NULL after it's free()'d)
0264 @RETURNS    : 
0265 @DESCRIPTION: Frees up an entire tree created by bt_build_tex_tree().
0266 @GLOBALS    : 
0267 @CALLS      : itself, free()
0268 @CALLERS    : 
0269 @CREATED    : 1997/05/29, GPW
0270 @MODIFIED   : 
0271 -------------------------------------------------------------------------- */
0272 void
0273 bt_free_tex_tree (bt_tex_tree **top)
0274 {
0275    if ((*top)->child) bt_free_tex_tree (&(*top)->child);
0276    if ((*top)->next) bt_free_tex_tree (&(*top)->next);
0277    free (*top);
0278    *top = NULL;
0279 }
0280 
0281 
0282 
0283 /* ----------------------------------------------------------------------
0284  * Tree traversal functions
0285  */
0286 
0287 /* ------------------------------------------------------------------------
0288 @NAME       : bt_dump_tex_tree
0289 @INPUT      : node
0290               depth
0291               stream
0292 @OUTPUT     : 
0293 @RETURNS    : 
0294 @DESCRIPTION: Dumps a TeX tree: one node per line, depth indented according
0295               to depth.
0296 @GLOBALS    : 
0297 @CALLS      : itself
0298 @CALLERS    : 
0299 @CREATED    : 1997/05/29, GPW
0300 @MODIFIED   : 
0301 -------------------------------------------------------------------------- */
0302 void
0303 bt_dump_tex_tree (bt_tex_tree *node, int depth, FILE *stream)
0304 {
0305    char  buf[256];
0306 
0307    if (node == NULL)
0308       return;
0309 
0310    if (node->len > 255)
0311       internal_error ("augughgh! buf too small");
0312    strncpy (buf, node->start, node->len);
0313    buf[node->len] = (char) 0;
0314 
0315    fprintf (stream, "%*s[%s]\n", depth*2, "", buf);
0316 
0317    bt_dump_tex_tree (node->child, depth+1, stream);
0318    bt_dump_tex_tree (node->next, depth, stream);
0319    
0320 }
0321 
0322 
0323 /* ------------------------------------------------------------------------
0324 @NAME       : count_length
0325 @INPUT      : node
0326 @OUTPUT     : 
0327 @RETURNS    : 
0328 @DESCRIPTION: Counts the total number of characters that will be needed
0329               to print a string reconstructed from a TeX tree.  (Length
0330               of string in each node, plus two [{ and }] for each down 
0331               edge.)
0332 @GLOBALS    : 
0333 @CALLS      : itself
0334 @CALLERS    : bt_flatten_tex_tree
0335 @CREATED    : 1997/05/29, GPW
0336 @MODIFIED   : 
0337 -------------------------------------------------------------------------- */
0338 static int
0339 count_length (bt_tex_tree *node)
0340 {
0341    if (node == NULL) return 0;
0342    return
0343       node->len + 
0344       (node->child ? 2 : 0) +
0345       count_length (node->child) +
0346       count_length (node->next);
0347 }
0348 
0349 
0350 /* ------------------------------------------------------------------------
0351 @NAME       : flatten_tree
0352 @INPUT      : node
0353               *offset
0354 @OUTPUT     : *buf
0355               *offset
0356 @RETURNS    : 
0357 @DESCRIPTION: Dumps a reconstructed string ("flat" representation of the 
0358               tree) into a pre-allocated buffer, starting at a specified
0359               offset.
0360 @GLOBALS    : 
0361 @CALLS      : itself
0362 @CALLERS    : bt_flatten_tex_tree
0363 @CREATED    : 1997/05/29, GPW
0364 @MODIFIED   : 
0365 -------------------------------------------------------------------------- */
0366 static void
0367 flatten_tree (bt_tex_tree *node, char *buf, int *offset)
0368 {
0369    strncpy (buf + *offset, node->start, node->len);
0370    *offset += node->len;
0371 
0372    if (node->child)
0373    {
0374       buf[(*offset)++] = '{';
0375       flatten_tree (node->child, buf, offset);
0376       buf[(*offset)++] = '}';
0377    }
0378 
0379    if (node->next)
0380    {
0381       flatten_tree (node->next, buf, offset);
0382    }
0383 }
0384 
0385 
0386 /* ------------------------------------------------------------------------
0387 @NAME       : bt_flatten_tex_tree
0388 @INPUT      : top
0389 @OUTPUT     : 
0390 @RETURNS    : flattened string representation of the tree (as a string
0391               allocated with malloc(), so you should free() it when 
0392               you're done with it)
0393 @DESCRIPTION: Counts the number of characters needed for a "flat"
0394               string representation of a tree, allocates a string of
0395               that size, and generates the string.
0396 @GLOBALS    : 
0397 @CALLS      : count_length, flatten_tree
0398 @CALLERS    : 
0399 @CREATED    : 1997/05/29, GPW
0400 @MODIFIED   : 
0401 -------------------------------------------------------------------------- */
0402 char *
0403 bt_flatten_tex_tree (bt_tex_tree *top)
0404 {
0405    int    len;
0406    int    offset;
0407    char * buf;
0408 
0409    len = count_length (top);
0410    buf = (char *) malloc (sizeof (char) * (len+1));
0411    offset = 0;
0412    flatten_tree (top, buf, &offset);
0413    return buf;
0414 }