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 }