1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- A program that merges multiple cachegrind output files.      ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                   cg_merge.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This file is part of Cachegrind, a Valgrind tool for cache
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  profiling programs.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov  Copyright (C) 2002-2013 Nicholas Nethercote
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     njn@valgrind.org
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  AVL tree code derived from
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  ANSI C Library for maintainance of AVL Balanced Trees
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  (C) 2000 Daniel Nagy, Budapest University of Technology and Economics
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Released under GNU General Public License (GPL) version 2
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This program is free software; you can redistribute it and/or
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  modify it under the terms of the GNU General Public License as
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  published by the Free Software Foundation; either version 2 of the
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  License, or (at your option) any later version.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This program is distributed in the hope that it will be useful, but
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  WITHOUT ANY WARRANTY; without even the implied warranty of
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  General Public License for more details.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  You should have received a copy of the GNU General Public License
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  along with this program; if not, write to the Free Software
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  02111-1307, USA.
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  The GNU General Public License is contained in the file COPYING.
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h>
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h>
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <ctype.h>
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  signed long   Word;
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  unsigned long UWord;
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  unsigned char Bool;
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define True ((Bool)1)
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define False ((Bool)0)
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  signed int    Int;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  unsigned int  UInt;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  unsigned long long int ULong;
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  signed char   Char;
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  size_t        SizeT;
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                           WordFM                           ---//
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                      Public interface                      ---//
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef  struct _WordFM  WordFM; /* opaque */
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Initialise a WordFM */
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid initFM ( WordFM* t,
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              void*   (*alloc_nofail)( SizeT ),
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              void    (*dealloc)(void*),
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              Word    (*kCmp)(Word,Word) );
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate and initialise a WordFM */
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWordFM* newFM( void* (*alloc_nofail)( SizeT ),
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               void  (*dealloc)(void*),
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Word  (*kCmp)(Word,Word) );
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Free up the FM.  If kFin is non-NULL, it is applied to keys
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   before the FM is deleted; ditto with vFin for vals. */
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid deleteFM ( WordFM*, void(*kFin)(Word), void(*vFin)(Word) );
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add (k,v) to fm.  If a binding for k already exists, it is updated
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to map to this new v.  In that case we should really return the
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   previous v so that caller can finalise it.  Oh well. */
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid addToFM ( WordFM* fm, Word k, Word v );
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Delete key from fm, returning associated val if found
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool delFromFM ( WordFM* fm, /*OUT*/Word* oldV, Word key );
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Look up in fm, assigning found val at spec'd address
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool lookupFM ( WordFM* fm, /*OUT*/Word* valP, Word key );
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWord sizeFM ( WordFM* fm );
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// set up FM for iteration
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid initIterFM ( WordFM* fm );
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// get next key/val pair.  Will assert if fm has been modified
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// or looked up in since initIterFM was called.
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool nextIterFM ( WordFM* fm, /*OUT*/Word* pKey, /*OUT*/Word* pVal );
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// clear the I'm iterating flag
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid doneIterFM ( WordFM* fm );
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Deep copy a FM.  If dopyK is NULL, keys are copied verbatim.
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// If non-null, dopyK is applied to each key to generate the
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// version in the new copy.  In that case, if the argument to dopyK
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// is non-NULL but the result is NULL, it is assumed that dopyK
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// could not allocate memory, in which case the copy is abandoned
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// and NULL is returned.  Ditto with dopyV for values.
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWordFM* dopyFM ( WordFM* fm, Word(*dopyK)(Word), Word(*dopyV)(Word) );
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                         end WordFM                         ---//
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                      Public interface                      ---//
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic const char* argv0 = "cg_merge";
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Keep track of source filename/line no so as to be able to
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   print decent error messages. */
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FILE* fp;
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt  lno;
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* filename;
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SOURCE;
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void printSrcLoc ( SOURCE* s )
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: near %s line %u\n", argv0, s->filename, s->lno-1);
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noreturn))
132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void mallocFail ( SOURCE* s, const char* who )
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: out of memory in %s\n", argv0, who );
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printSrcLoc( s );
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exit(2);
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noreturn))
140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void parseError ( SOURCE* s, const char* msg )
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: parse error: %s\n", argv0, msg );
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printSrcLoc( s );
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exit(1);
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((noreturn))
148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void barf ( SOURCE* s, const char* msg )
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: %s\n", argv0, msg );
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   printSrcLoc( s );
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exit(1);
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Read a line
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define M_LINEBUF 40960
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic char line[M_LINEBUF];
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// True if anything read, False if at EOF
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool readline ( SOURCE* s )
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int ch, i = 0;
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   line[0] = 0;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (i >= M_LINEBUF-10)
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parseError(s, "Unexpected long line in input file");
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ch = getc(s->fp);
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ch != EOF) {
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          line[i++] = ch;
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          line[i] = 0;
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if (ch == '\n') {
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             line[i-1] = 0;
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             s->lno++;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             break;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          }
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (ferror(s->fp)) {
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            perror(argv0);
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            barf(s, "I/O error while reading input file");
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // hit EOF
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return line[0] != 0;
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool streqn ( const char* s1, const char* s2, size_t n )
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0 == strncmp(s1, s2, n);
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
194436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool streq ( const char* s1, const char* s2 )
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0 == strcmp(s1, s2 );
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown////////////////////////////////////////////////////////////////
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* fi_name;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* fn_name;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int n_counts;
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong* counts;
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts;
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // null-terminated vector of desc_lines
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char** desc_lines;
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Cmd line
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* cmd_line;
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Events line
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* events_line;
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int   n_events;
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Summary line (copied from input)
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      char* summary_line;
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Outermost map is
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            WordFM FileFn* innerMap
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         where innerMap is   WordFM line-number=UWord Counts */
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      WordFM* outerMap;
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Summary counts (computed whilst parsing)
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // should match .summary_line
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Counts* summary;
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CacheProfFile;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic FileFn* new_FileFn ( char* file_name, char* fn_name )
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* ffn = malloc(sizeof(FileFn));
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ffn == NULL)
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ffn->fi_name = file_name;
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ffn->fn_name = fn_name;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ffn;
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ddel_FileFn ( FileFn* ffn )
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ffn->fi_name)
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(ffn->fi_name);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ffn->fn_name)
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(ffn->fn_name);
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(ffn, 0, sizeof(FileFn));
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   free(ffn);
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic FileFn* dopy_FileFn ( FileFn* ff )
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char* fi2 = strdup(ff->fi_name);
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char* fn2 = strdup(ff->fn_name);
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((!fi2) || (!fn2))
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return new_FileFn( fi2, fn2 );
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Counts* new_Counts ( Int n_counts, /*COPIED*/ULong* counts )
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* cts = malloc(sizeof(Counts));
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cts == NULL)
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(n_counts >= 0);
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cts->counts = malloc(n_counts * sizeof(ULong));
280436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (cts->counts == NULL) {
281436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      free(cts);
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
283436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cts->n_counts = n_counts;
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_counts; i++)
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cts->counts[i] = counts[i];
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return cts;
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Counts* new_Counts_Zeroed ( Int n_counts )
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* cts = malloc(sizeof(Counts));
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cts == NULL)
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(n_counts >= 0);
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cts->counts = malloc(n_counts * sizeof(ULong));
301436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (cts->counts == NULL) {
302436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      free(cts);
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
304436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cts->n_counts = n_counts;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_counts; i++)
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cts->counts[i] = 0;
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return cts;
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sdel_Counts ( Counts* cts )
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(cts, 0, sizeof(Counts));
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   free(cts);
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ddel_Counts ( Counts* cts )
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cts->counts)
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cts->counts);
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(cts, 0, sizeof(Counts));
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   free(cts);
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Counts* dopy_Counts ( Counts* cts )
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return new_Counts( cts->n_counts, cts->counts );
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownCacheProfFile* new_CacheProfFile ( char**  desc_lines,
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   char*   cmd_line,
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   char*   events_line,
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   Int     n_events,
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   char*   summary_line,
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   WordFM* outerMap,
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   Counts* summary )
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CacheProfFile* cpf = malloc(sizeof(CacheProfFile));
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf == NULL)
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->desc_lines   = desc_lines;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->cmd_line     = cmd_line;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->events_line  = events_line;
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->n_events     = n_events;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->summary_line = summary_line;
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->outerMap     = outerMap;
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->summary      = summary;
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return cpf;
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* dopy_InnerMap ( WordFM* innerMap )
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dopyFM ( innerMap, NULL,
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             (Word(*)(Word))dopy_Counts );
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ddel_InnerMap ( WordFM* innerMap )
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   deleteFM( innerMap, NULL, (void(*)(Word))ddel_Counts );
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ddel_CacheProfFile ( CacheProfFile* cpf )
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char** p;
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->desc_lines) {
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (p = cpf->desc_lines; *p; p++)
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         free(*p);
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cpf->desc_lines);
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->cmd_line)
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cpf->cmd_line);
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->events_line)
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cpf->events_line);
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->summary_line)
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cpf->summary_line);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->outerMap)
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      deleteFM( cpf->outerMap, (void(*)(Word))ddel_FileFn,
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               (void(*)(Word))ddel_InnerMap );
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->summary)
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ddel_Counts(cpf->summary);
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(cpf, 0, sizeof(CacheProfFile));
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   free(cpf);
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void showCounts ( FILE* f, Counts* c )
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < c->n_counts; i++) {
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(f, "%lld ", c->counts[i]);
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void show_CacheProfFile ( FILE* f, CacheProfFile* cpf )
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     i;
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char**  d;
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* topKey;
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* topVal;
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   subKey;
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* subVal;
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (d = cpf->desc_lines; *d; d++)
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(f, "%s\n", *d);
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(f, "%s\n", cpf->cmd_line);
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(f, "%s\n", cpf->events_line);
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   initIterFM( cpf->outerMap );
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (nextIterFM( cpf->outerMap, (Word*)(&topKey), (Word*)(&topVal) )) {
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(f, "fl=%s\nfn=%s\n",
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 topKey->fi_name, topKey->fn_name );
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      initIterFM( topVal );
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (nextIterFM( topVal, (Word*)(&subKey), (Word*)(&subVal) )) {
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fprintf(f, "%ld   ", subKey );
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         showCounts( f, subVal );
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fprintf(f, "\n");
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      doneIterFM( topVal );
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   doneIterFM( cpf->outerMap );
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //fprintf(f, "%s\n", cpf->summary_line);
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(f, "summary:");
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < cpf->summary->n_counts; i++)
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(f, " %lld", cpf->summary->counts[i]);
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(f, "\n");
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown////////////////////////////////////////////////////////////////
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word cmp_FileFn ( Word s1, Word s2 )
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* ff1 = (FileFn*)s1;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* ff2 = (FileFn*)s2;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word r = strcmp(ff1->fi_name, ff2->fi_name);
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (r == 0)
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      r = strcmp(ff1->fn_name, ff2->fn_name);
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return r;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word cmp_unboxed_UWord ( Word s1, Word s2 )
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord u1 = (UWord)s1;
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord u2 = (UWord)s2;
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (u1 < u2) return -1;
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (u1 > u2) return 1;
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown////////////////////////////////////////////////////////////////
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool parse_ULong ( /*OUT*/ULong* res, /*INOUT*/char** pptr)
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong u64;
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char* ptr = *pptr;
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (isspace(*ptr)) ptr++;
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isdigit(*ptr)) {
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *pptr = ptr;
462436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      return False; /* end of string, or junk */
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   u64 = 0;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (isdigit(*ptr)) {
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      u64 = (u64 * 10) + (ULong)(*ptr - '0');
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ptr++;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *res = u64;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *pptr = ptr;
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// str is a line of digits, starting with a line number.  Parse it,
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// returning the first number in *lnno and the rest in a newly
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// allocated Counts struct.  If lnno is non-NULL, treat the first
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// number as a line number and assign it to *lnno instead of
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// incorporating it in the counts array.
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownCounts* splitUpCountsLine ( SOURCE* s, /*OUT*/UWord* lnno, char* str )
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_TMPC 50
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    ok;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* counts;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong   tmpC[N_TMPC];
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     n_tmpC = 0;
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ok = parse_ULong( &tmpC[n_tmpC], &str );
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok)
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_tmpC++;
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_tmpC >= N_TMPC)
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         barf(s, "N_TMPC too low.  Increase and recompile.");
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (*str != 0)
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "garbage in counts line");
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lnno ? (n_tmpC < 2) : (n_tmpC < 1))
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "too few counts in count line");
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lnno) {
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *lnno = (UWord)tmpC[0];
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      counts = new_Counts( n_tmpC-1, /*COPIED*/&tmpC[1] );
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      counts = new_Counts( n_tmpC, /*COPIED*/&tmpC[0] );
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return counts;
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef N_TMPC
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void addCounts ( SOURCE* s, /*OUT*/Counts* counts1, Counts* counts2 )
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (counts1->n_counts != counts2->n_counts)
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "addCounts: inconsistent number of counts");
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < counts1->n_counts; i++)
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      counts1->counts[i] += counts2->counts[i];
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool addCountsToMap ( SOURCE* s,
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             WordFM* counts_map,
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             UWord lnno, Counts* newCounts )
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* oldCounts;
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // look up lnno in the map.  If none present, add a binding
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // lnno->counts.  If present, add counts to the existing entry.
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lookupFM( counts_map, (Word*)(&oldCounts), (Word)lnno )) {
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // merge with existing binding
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addCounts( s, oldCounts, newCounts );
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // create new binding
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addToFM( counts_map, (Word)lnno, (Word)newCounts );
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid handle_counts ( SOURCE* s,
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     CacheProfFile* cpf,
541436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                     const char* fi, const char* fn, char* newCountsStr )
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* countsMap;
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    freeNewCounts;
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   lnno;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* newCounts;
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* topKey;
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0)  printf("%s %s %s\n", fi, fn, newCountsStr );
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // parse the numbers
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newCounts = splitUpCountsLine( s, &lnno, newCountsStr );
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Did we get the right number?
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newCounts->n_counts != cpf->n_events)
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto oom;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // allocate the key
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   topKey = malloc(sizeof(FileFn));
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (topKey) {
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      topKey->fi_name = strdup(fi);
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      topKey->fn_name = strdup(fn);
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! (topKey && topKey->fi_name && topKey->fn_name))
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "handle_counts:");
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // search for it
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lookupFM( cpf->outerMap, (Word*)(&countsMap), (Word)topKey )) {
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // found it.  Merge in new counts
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts );
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ddel_FileFn(topKey);
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // not found in the top map.  Create new entry
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      countsMap = newFM( malloc, free, cmp_unboxed_UWord );
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!countsMap)
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto oom;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addToFM( cpf->outerMap, (Word)topKey, (Word)countsMap );
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts );
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // also add to running summary total
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addCounts( s, cpf->summary, newCounts );
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // if safe to do so, free up the count vector
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (freeNewCounts)
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ddel_Counts(newCounts);
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  oom:
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   parseError(s, "# counts doesn't match # events");
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Parse a complete file from the stream in 's'.  If a parse error
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happens, do not return; instead exit via parseError().  If an
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   out-of-memory condition happens, do not return; instead exit via
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mallocError().
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic CacheProfFile* parse_CacheProfFile ( SOURCE* s )
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define M_TMP_DESCLINES 10
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int            i;
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool           b;
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char*          tmp_desclines[M_TMP_DESCLINES];
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char*          p;
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   int            n_tmp_desclines = 0;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CacheProfFile* cpf;
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts*        summaryRead;
611436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   char*          curr_fn = strdup("???");
612436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   char*          curr_fl = strdup("???");
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf = new_CacheProfFile( NULL, NULL, NULL, 0, NULL, NULL, NULL );
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf == NULL)
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(1)");
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Parse "desc:" lines
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      b = readline(s);
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!b)
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!streqn(line, "desc: ", 6))
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_tmp_desclines >= M_TMP_DESCLINES)
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         barf(s, "M_TMP_DESCLINES too low; increase and recompile");
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmp_desclines[n_tmp_desclines++] = strdup(line);
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n_tmp_desclines == 0)
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: no DESC lines present");
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->desc_lines = malloc( (1+n_tmp_desclines) * sizeof(char*) );
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->desc_lines == NULL)
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(2)");
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->desc_lines[n_tmp_desclines] = NULL;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < n_tmp_desclines; i++)
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cpf->desc_lines[i] = tmp_desclines[i];
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Parse "cmd:" line
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!streqn(line, "cmd: ", 5))
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: no CMD line present");
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->cmd_line = strdup(line);
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->cmd_line == NULL)
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(3)");
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Parse "events:" line and figure out how many events there are
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   b = readline(s);
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!b)
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: eof before EVENTS line");
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!streqn(line, "events: ", 8))
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: no EVENTS line present");
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // figure out how many events there are by counting the number
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // of space-alphanum transitions in the events_line
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->events_line = strdup(line);
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->events_line == NULL)
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(3)");
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->n_events = 0;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(cpf->events_line[6] == ':');
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (p = &cpf->events_line[6]; *p; p++) {
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] == ' ' && isalpha(p[1]))
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cpf->n_events++;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // create the running cross-check summary
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->summary = new_Counts_Zeroed( cpf->n_events );
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->summary == NULL)
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(4)");
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // create the outer map (file+fn name --> inner map)
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->outerMap = newFM ( malloc, free, cmp_FileFn );
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->outerMap == NULL)
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(5)");
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // process count lines
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      b = readline(s);
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!b)
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parseError(s, "parse_CacheProfFile: eof before SUMMARY line");
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isdigit(line[0])) {
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         handle_counts(s, cpf, curr_fl, curr_fn, line);
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (streqn(line, "fn=", 3)) {
691436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         free(curr_fn);
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_fn = strdup(line+3);
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (streqn(line, "fl=", 3)) {
697436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         free(curr_fl);
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_fl = strdup(line+3);
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (streqn(line, "summary: ", 9)) {
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parseError(s, "parse_CacheProfFile: unexpected line in main data");
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // finally, the "summary:" line
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!streqn(line, "summary: ", 9))
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: missing SUMMARY line");
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf->summary_line = strdup(line);
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->summary_line == NULL)
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(6)");
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // there should be nothing more
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   b = readline(s);
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (b)
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: "
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "extraneous content after SUMMARY line");
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // check the summary counts are as expected
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   summaryRead = splitUpCountsLine( s, NULL, &cpf->summary_line[8] );
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (summaryRead == NULL)
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mallocFail(s, "parse_CacheProfFile(7)");
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (summaryRead->n_counts != cpf->n_events)
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parseError(s, "parse_CacheProfFile: wrong # counts in SUMMARY line");
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < summaryRead->n_counts; i++) {
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (summaryRead->counts[i] != cpf->summary->counts[i]) {
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         parseError(s, "parse_CacheProfFile: "
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "computed vs stated SUMMARY counts mismatch");
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   free(summaryRead->counts);
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sdel_Counts(summaryRead);
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // since the summary counts are OK, free up the summary_line text
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // which contains the same info.
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf->summary_line) {
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(cpf->summary_line);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cpf->summary_line = NULL;
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free(curr_fn);
746436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free(curr_fl);
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // All looks OK
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return cpf;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef N_TMP_DESCLINES
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void merge_CacheProfInfo ( SOURCE* s,
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  /*MOD*/CacheProfFile* dst,
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  CacheProfFile* src )
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* For each (filefn, innerMap) in src
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if filefn not in dst
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         add binding dopy(filefn)->dopy(innerMap) in src
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // merge src->innerMap with dst->innerMap
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for each (lineno, counts) in src->innerMap
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if lineno not in dst->innerMap
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add binding lineno->dopy(counts) to dst->innerMap
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add counts into dst->innerMap[lineno]
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Outer iterator:  FileFn* -> WordFM* (inner iterator)
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Inner iterator:  UWord   -> Counts*
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FileFn* soKey;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* soVal;
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* doVal;
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord   siKey;
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* siVal;
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Counts* diVal;
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First check mundane things: that the events: lines are
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      identical. */
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!streq( dst->events_line, src->events_line ))
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     barf(s, "\"events:\" line of most recent file does "
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "not match those previously processed");
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   initIterFM( src->outerMap );
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // for (filefn, innerMap) in src
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (nextIterFM( src->outerMap, (Word*)&soKey, (Word*)&soVal )) {
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // is filefn in dst?
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (! lookupFM( dst->outerMap, (Word*)&doVal, (Word)soKey )) {
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // no .. add dopy(filefn) -> dopy(innerMap) to src
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         FileFn* c_soKey = dopy_FileFn(soKey);
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         WordFM* c_soVal = dopy_InnerMap(soVal);
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((!c_soKey) || (!c_soVal)) goto oom;
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addToFM( dst->outerMap, (Word)c_soKey, (Word)c_soVal );
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // yes .. merge the two innermaps
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         initIterFM( soVal );
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // for (lno, counts) in soVal (source inner map)
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         while (nextIterFM( soVal, (Word*)&siKey, (Word*)&siVal )) {
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            // is lno in the corresponding dst inner map?
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (! lookupFM( doVal, (Word*)&diVal, siKey )) {
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // no .. add lineno->dopy(counts) to dst inner map
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Counts* c_siVal = dopy_Counts( siVal );
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!c_siVal) goto oom;
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addToFM( doVal, siKey, (Word)c_siVal );
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               // yes .. merge counts into dst inner map val
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               addCounts( s, diVal, siVal );
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // add the summaries too
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addCounts(s, dst->summary, src->summary );
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return;
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  oom:
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mallocFail(s, "merge_CacheProfInfo");
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void usage ( void )
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: Merges multiple cachegrind output files into one\n",
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   argv0);
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fprintf(stderr, "%s: usage: %s [-o outfile] [files-to-merge]\n",
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   argv0, argv0);
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   exit(1);
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main ( int argc, char** argv )
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int            i;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SOURCE         src;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CacheProfFile  *cpf, *cpfTmp;
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FILE*          outfile = NULL;
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   char*          outfilename = NULL;
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int            outfileix = 0;
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (argv[0])
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argv0 = argv[0];
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (argc < 2)
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      usage();
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < argc; i++) {
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (streq(argv[i], "-h") || streq(argv[i], "--help"))
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         usage();
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Scan args, looking for '-o outfilename'. */
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < argc; i++) {
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (streq(argv[i], "-o")) {
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (i+1 < argc) {
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            outfilename = argv[i+1];
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            outfileix   = i;
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            usage();
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cpf = NULL;
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < argc; i++) {
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (i == outfileix) {
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Skip '-o' and whatever follows it */
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         i += 1;
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(stderr, "%s: parsing %s\n", argv0, argv[i]);
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      src.lno      = 1;
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      src.filename = argv[i];
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      src.fp       = fopen(src.filename, "r");
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!src.fp) {
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         perror(argv0);
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         barf(&src, "Cannot open input file");
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(src.fp);
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cpfTmp = parse_CacheProfFile( &src );
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fclose(src.fp);
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If this isn't the first file, merge */
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cpf == NULL) {
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* this is the first file */
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cpf = cpfTmp;
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* not the first file; merge */
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fprintf(stderr, "%s: merging %s\n", argv0, argv[i]);
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         merge_CacheProfInfo( &src, cpf, cpfTmp );
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ddel_CacheProfFile( cpfTmp );
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now create the output file. */
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cpf) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fprintf(stderr, "%s: writing %s\n",
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       argv0, outfilename ? outfilename : "(stdout)" );
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Write the output. */
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (outfilename) {
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         outfile = fopen(outfilename, "w");
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!outfile) {
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fprintf(stderr, "%s: can't create output file %s\n",
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            argv0, outfilename);
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            perror(argv0);
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            exit(1);
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         outfile = stdout;
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      show_CacheProfFile( outfile, cpf );
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ferror(outfile)) {
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fprintf(stderr, "%s: error writing output file %s\n",
938b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         argv0, outfilename ? outfilename : "(stdout)" );
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         perror(argv0);
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (outfile != stdout)
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fclose(outfile);
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         exit(1);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fflush(outfile);
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (outfile != stdout)
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fclose( outfile );
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ddel_CacheProfFile( cpf );
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                           WordFM                           ---//
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                       Implementation                       ---//
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------ Implementation ------------ */
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* One element of the AVL tree */
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct _AvlNode {
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word key;
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word val;
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _AvlNode* left;
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      struct _AvlNode* right;
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Char balance;
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode;
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Word w;
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool b;
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MaybeWord;
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define WFM_STKMAX    32    // At most 2**32 entries can be iterated over
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct _WordFM {
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* root;
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*    (*alloc_nofail)( SizeT );
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void     (*dealloc)(void*);
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word     (*kCmp)(Word,Word);
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* nodeStack[WFM_STKMAX]; // Iterator node stack
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      numStack[WFM_STKMAX];  // Iterator num stack
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int      stackTop;              // Iterator stack pointer, one past end
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* forward */
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool avl_removeroot_wrk(AvlNode** t, Word(*kCmp)(Word,Word));
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Swing to the left.  Warning: no balance maintainance. */
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void avl_swl ( AvlNode** root )
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* a = *root;
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* b = a->right;
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *root    = b;
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->right = b->left;
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   b->left  = a;
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Swing to the right.  Warning: no balance maintainance. */
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void avl_swr ( AvlNode** root )
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* a = *root;
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* b = a->left;
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *root    = b;
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->left  = b->right;
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   b->right = a;
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Balance maintainance after especially nasty swings. */
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void avl_nasty ( AvlNode* root )
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (root->balance) {
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case -1:
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->left->balance  = 0;
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->right->balance = 1;
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->left->balance  = -1;
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->right->balance = 0;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->left->balance  = 0;
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         root->right->balance = 0;
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assert(0);
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   root->balance=0;
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Find size of a non-NULL tree. */
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word size_avl_nonNull ( AvlNode* nd )
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 1 + (nd->left  ? size_avl_nonNull(nd->left)  : 0)
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            + (nd->right ? size_avl_nonNull(nd->right) : 0);
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Insert element a into the AVL tree t.  Returns True if the depth of
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the tree has grown.  If element with that key is already present,
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   just copy a->val to existing node, first returning old ->val field
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of existing node in *oldV, so that the caller can finalize it
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   however it wants.
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool avl_insert_wrk ( AvlNode**         rootp,
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      /*OUT*/MaybeWord* oldV,
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      AvlNode*          a,
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Word              (*kCmp)(Word,Word) )
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word cmpres;
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* initialize */
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->left    = 0;
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->right   = 0;
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->balance = 0;
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oldV->b    = False;
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* insert into an empty tree? */
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(*rootp)) {
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp) = a;
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cmpres = kCmp( (*rootp)->key, a->key );
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cmpres > 0) {
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* insert into the left subtree */
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((*rootp)->left) {
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         AvlNode* left_subtree = (*rootp)->left;
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (avl_insert_wrk(&left_subtree, oldV, a, kCmp)) {
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch ((*rootp)->balance--) {
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case  1: return False;
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case  0: return True;
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case -1: break;
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: assert(0);
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((*rootp)->left->balance < 0) {
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swr( rootp );
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = 0;
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->right->balance = 0;
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swl( &((*rootp)->left) );
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swr( rootp );
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_nasty( *rootp );
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (*rootp)->left = left_subtree;
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (*rootp)->left = a;
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((*rootp)->balance--)
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(0);/*NOTREACHED*/
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cmpres < 0) {
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* insert into the right subtree */
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((*rootp)->right) {
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         AvlNode* right_subtree = (*rootp)->right;
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (avl_insert_wrk(&right_subtree, oldV, a, kCmp)) {
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            switch((*rootp)->balance++){
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case -1: return False;
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case  0: return True;
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               case  1: break;
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               default: assert(0);
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ((*rootp)->right->balance > 0) {
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swl( rootp );
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = 0;
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->left->balance = 0;
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swr( &((*rootp)->right) );
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swl( rootp );
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_nasty( *rootp );
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (*rootp)->right = right_subtree;
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return False;
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (*rootp)->right = a;
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((*rootp)->balance++)
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return False;
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(0);/*NOTREACHED*/
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* cmpres == 0, a duplicate - replace the val, but don't
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         incorporate the node in the tree */
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      oldV->b = True;
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      oldV->w = (*rootp)->val;
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp)->val = a->val;
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Remove an element a from the AVL tree t.  a must be part of
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the tree.  Returns True if the depth of the tree has shrunk.
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool avl_remove_wrk ( AvlNode** rootp,
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      AvlNode*  a,
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Word(*kCmp)(Word,Word) )
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool ch;
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word cmpres = kCmp( (*rootp)->key, a->key );
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cmpres > 0){
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* remove from the left subtree */
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      AvlNode* left_subtree = (*rootp)->left;
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(left_subtree);
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ch = avl_remove_wrk(&left_subtree, a, kCmp);
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp)->left=left_subtree;
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ch) {
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch ((*rootp)->balance++) {
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -1: return True;
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  0: return False;
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  1: break;
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: assert(0);
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch ((*rootp)->right->balance) {
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swl( rootp );
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = -1;
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->left->balance = 1;
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swl( rootp );
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = 0;
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->left->balance = 0;
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return -1;
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -1:
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assert(0);
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_swr( &((*rootp)->right) );
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_swl( rootp );
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_nasty( *rootp );
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cmpres < 0) {
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* remove from the right subtree */
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      AvlNode* right_subtree = (*rootp)->right;
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(right_subtree);
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ch = avl_remove_wrk(&right_subtree, a, kCmp);
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp)->right = right_subtree;
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ch) {
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch ((*rootp)->balance--) {
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  1: return True;
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  0: return False;
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -1: break;
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: assert(0);
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch ((*rootp)->left->balance) {
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swr( rootp );
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = 1;
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->right->balance = -1;
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return False;
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -1:
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               avl_swr( rootp );
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->balance = 0;
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (*rootp)->right->balance = 0;
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               return True;
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assert(0);
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_swl( &((*rootp)->left) );
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_swr( rootp );
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         avl_nasty( *rootp );
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(cmpres == 0);
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert((*rootp)==a);
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return avl_removeroot_wrk(rootp, kCmp);
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Remove the root of the AVL tree *rootp.
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Warning: dumps core if *rootp is empty
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool avl_removeroot_wrk ( AvlNode** rootp,
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Word(*kCmp)(Word,Word) )
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool     ch;
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* a;
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(*rootp)->left) {
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(*rootp)->right) {
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (*rootp) = 0;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp) = (*rootp)->right;
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(*rootp)->right) {
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (*rootp) = (*rootp)->left;
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((*rootp)->balance < 0) {
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* remove from the left subtree */
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a = (*rootp)->left;
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (a->right) a = a->right;
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* remove from the right subtree */
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a = (*rootp)->right;
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (a->left) a = a->left;
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ch = avl_remove_wrk(rootp, a, kCmp);
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->left    = (*rootp)->left;
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->right   = (*rootp)->right;
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a->balance = (*rootp)->balance;
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (*rootp)   = a;
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if(a->balance == 0) return ch;
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAvlNode* avl_find_node ( AvlNode* t, Word k, Word(*kCmp)(Word,Word) )
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word cmpres;
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (t == NULL) return NULL;
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmpres = kCmp(t->key, k);
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cmpres > 0) t = t->left;  else
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (cmpres < 0) t = t->right; else
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return t;
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Clear the iterator stack.
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void stackClear(WordFM* fm)
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm);
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < WFM_STKMAX; i++) {
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm->nodeStack[i] = NULL;
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm->numStack[i]  = 0;
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->stackTop = 0;
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Push onto the iterator stack.
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline void stackPush(WordFM* fm, AvlNode* n, Int i)
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm->stackTop < WFM_STKMAX);
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(1 <= i && i <= 3);
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->nodeStack[fm->stackTop] = n;
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm-> numStack[fm->stackTop] = i;
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->stackTop++;
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Pop from the iterator stack.
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Bool stackPop(WordFM* fm, AvlNode** n, Int* i)
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm->stackTop <= WFM_STKMAX);
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (fm->stackTop > 0) {
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm->stackTop--;
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *n = fm->nodeStack[fm->stackTop];
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *i = fm-> numStack[fm->stackTop];
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(1 <= *i && *i <= 3);
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm->nodeStack[fm->stackTop] = NULL;
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm-> numStack[fm->stackTop] = 0;
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAvlNode* avl_dopy ( AvlNode* nd,
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Word(*dopyK)(Word),
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Word(*dopyV)(Word),
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    void*(alloc_nofail)(SizeT) )
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* nyu;
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! nd)
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return NULL;
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nyu = alloc_nofail(sizeof(AvlNode));
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(nyu);
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nyu->left = nd->left;
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nyu->right = nd->right;
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nyu->balance = nd->balance;
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy key */
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dopyK) {
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->key = dopyK( nd->key );
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (nd->key != 0 && nyu->key == 0)
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL; /* oom in key dcopy */
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* copying assumedly unboxed keys */
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->key = nd->key;
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy val */
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dopyV) {
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->val = dopyV( nd->val );
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (nd->val != 0 && nyu->val == 0)
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL; /* oom in val dcopy */
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* copying assumedly unboxed vals */
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->val = nd->val;
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy subtrees */
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nyu->left) {
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->left = avl_dopy( nyu->left, dopyK, dopyV, alloc_nofail );
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (! nyu->left)
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL;
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nyu->right) {
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->right = avl_dopy( nyu->right, dopyK, dopyV, alloc_nofail );
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (! nyu->right)
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL;
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nyu;
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Public interface functions --- */
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Initialise a WordFM. */
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid initFM ( WordFM* fm,
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              void*   (*alloc_nofail)( SizeT ),
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              void    (*dealloc)(void*),
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              Word    (*kCmp)(Word,Word) )
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->root         = 0;
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->kCmp         = kCmp;
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->alloc_nofail = alloc_nofail;
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->dealloc      = dealloc;
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->stackTop     = 0;
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Allocate and Initialise a WordFM. */
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWordFM* newFM( void* (*alloc_nofail)( SizeT ),
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               void  (*dealloc)(void*),
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Word  (*kCmp)(Word,Word) )
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* fm = alloc_nofail(sizeof(WordFM));
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm);
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   initFM(fm, alloc_nofail, dealloc, kCmp);
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return fm;
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void avl_free ( AvlNode* nd,
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       void(*kFin)(Word),
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       void(*vFin)(Word),
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       void(*dealloc)(void*) )
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!nd)
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nd->left)
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      avl_free(nd->left, kFin, vFin, dealloc);
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nd->right)
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      avl_free(nd->right, kFin, vFin, dealloc);
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (kFin)
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kFin( nd->key );
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vFin)
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vFin( nd->val );
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(nd, 0, sizeof(AvlNode));
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dealloc(nd);
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Free up the FM.  If kFin is non-NULL, it is applied to keys
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   before the FM is deleted; ditto with vFin for vals. */
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid deleteFM ( WordFM* fm, void(*kFin)(Word), void(*vFin)(Word) )
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void(*dealloc)(void*) = fm->dealloc;
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   avl_free( fm->root, kFin, vFin, dealloc );
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(fm, 0, sizeof(WordFM) );
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dealloc(fm);
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add (k,v) to fm. */
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid addToFM ( WordFM* fm, Word k, Word v )
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MaybeWord oldV;
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* node;
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   node = fm->alloc_nofail( sizeof(struct _AvlNode) );
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   node->key = k;
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   node->val = v;
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oldV.b = False;
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   oldV.w = 0;
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   avl_insert_wrk( &fm->root, &oldV, node, fm->kCmp );
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //if (oldV.b && fm->vFin)
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   fm->vFin( oldV.w );
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (oldV.b)
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      free(node);
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Delete key from fm, returning associated val if found
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool delFromFM ( WordFM* fm, /*OUT*/Word* oldV, Word key )
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (node) {
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      avl_remove_wrk( &fm->root, node, fm->kCmp );
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (oldV)
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *oldV = node->val;
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fm->dealloc(node);
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Look up in fm, assigning found val at spec'd address
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool lookupFM ( WordFM* fm, /*OUT*/Word* valP, Word key )
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* node = avl_find_node( fm->root, key, fm->kCmp );
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (node) {
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (valP)
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *valP = node->val;
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWord sizeFM ( WordFM* fm )
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Hmm, this is a bad way to do this
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return fm->root ? size_avl_nonNull( fm->root ) : 0;
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// set up FM for iteration
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid initIterFM ( WordFM* fm )
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm);
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stackClear(fm);
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (fm->root)
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stackPush(fm, fm->root, 1);
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// get next key/val pair.  Will assert if fm has been modified
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// or looked up in since initIterFM was called.
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool nextIterFM ( WordFM* fm, /*OUT*/Word* pKey, /*OUT*/Word* pVal )
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i = 0;
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AvlNode* n = NULL;
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm);
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // This in-order traversal requires each node to be pushed and popped
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // three times.  These could be avoided by updating nodes in-situ on the
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // top of the stack, but the push/pop cost is so small that it's worth
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // keeping this loop in this simpler form.
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (stackPop(fm, &n, &i)) {
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (i) {
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stackPush(fm, n, 2);
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (n->left)  stackPush(fm, n->left, 1);
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stackPush(fm, n, 3);
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pKey) *pKey = n->key;
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pVal) *pVal = n->val;
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (n->right) stackPush(fm, n->right, 1);
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assert(0);
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Stack empty, iterator is exhausted, return NULL
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// clear the I'm iterating flag
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid doneIterFM ( WordFM* fm )
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownWordFM* dopyFM ( WordFM* fm, Word(*dopyK)(Word), Word(*dopyV)(Word) )
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WordFM* nyu;
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* can't clone the fm whilst iterating on it */
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(fm->stackTop == 0);
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nyu = fm->alloc_nofail( sizeof(WordFM) );
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assert(nyu);
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *nyu = *fm;
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fm->stackTop = 0;
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(fm->nodeStack, 0, sizeof(fm->nodeStack));
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memset(fm->numStack, 0,  sizeof(fm->numStack));
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (nyu->root) {
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nyu->root = avl_dopy( nyu->root, dopyK, dopyV, fm->alloc_nofail );
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (! nyu->root)
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return NULL;
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nyu;
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                         end WordFM                         ---//
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//---                       Implementation                       ---//
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//------------------------------------------------------------------//
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                               cg_merge.c ---*/
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1570