Compare commits
2 Commits
jnance_str
...
MY_FOO_BRA
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae74ac3c3b | ||
|
|
104d04c16a |
File diff suppressed because it is too large
Load Diff
@@ -1,219 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab:
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsFontMetricsGTK_h__
|
||||
#define nsFontMetricsGTK_h__
|
||||
|
||||
#include "nsDeviceContextGTK.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsIFontEnumerator.h"
|
||||
#include "nsFont.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnitConversion.h"
|
||||
#include "nsIDeviceContext.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsRenderingContextGTK.h"
|
||||
#include "nsICharRepresentable.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
#undef FONT_HAS_GLYPH
|
||||
#define FONT_HAS_GLYPH(map, char) IS_REPRESENTABLE(map, char)
|
||||
|
||||
typedef struct nsFontCharSetInfo nsFontCharSetInfo;
|
||||
|
||||
typedef gint (*nsFontCharSetConverter)(nsFontCharSetInfo* aSelf,
|
||||
XFontStruct* aFont, const PRUnichar* aSrcBuf, PRInt32 aSrcLen,
|
||||
char* aDestBuf, PRInt32 aDestLen);
|
||||
|
||||
struct nsFontCharSet;
|
||||
struct nsFontFamily;
|
||||
struct nsFontNode;
|
||||
struct nsFontStretch;
|
||||
|
||||
class nsFontGTKUserDefined;
|
||||
class nsFontMetricsGTK;
|
||||
|
||||
class nsFontGTK
|
||||
{
|
||||
public:
|
||||
nsFontGTK();
|
||||
virtual ~nsFontGTK();
|
||||
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
||||
|
||||
void LoadFont(void);
|
||||
PRBool IsEmptyFont(GdkFont*);
|
||||
|
||||
inline int SupportsChar(PRUnichar aChar)
|
||||
{ return mFont && FONT_HAS_GLYPH(mMap, aChar); };
|
||||
|
||||
virtual GdkFont* GetGDKFont(void);
|
||||
virtual PRBool GetGDKFontIs10646(void);
|
||||
virtual gint GetWidth(const PRUnichar* aString, PRUint32 aLength) = 0;
|
||||
virtual gint DrawString(nsRenderingContextGTK* aContext,
|
||||
nsDrawingSurfaceGTK* aSurface, nscoord aX,
|
||||
nscoord aY, const PRUnichar* aString,
|
||||
PRUint32 aLength) = 0;
|
||||
#ifdef MOZ_MATHML
|
||||
// bounding metrics for a string
|
||||
// remember returned values are not in app units
|
||||
// - to emulate GetWidth () above
|
||||
virtual nsresult
|
||||
GetBoundingMetrics(const PRUnichar* aString,
|
||||
PRUint32 aLength,
|
||||
nsBoundingMetrics& aBoundingMetrics) = 0;
|
||||
#endif
|
||||
|
||||
PRUint32* mMap;
|
||||
nsFontCharSetInfo* mCharSetInfo;
|
||||
char* mName;
|
||||
nsFontGTKUserDefined* mUserDefinedFont;
|
||||
PRUint16 mSize;
|
||||
PRInt16 mBaselineAdjust;
|
||||
|
||||
protected:
|
||||
GdkFont* mFont;
|
||||
PRBool mAlreadyCalledLoadFont;
|
||||
};
|
||||
|
||||
class nsFontMetricsGTK : public nsIFontMetrics
|
||||
{
|
||||
public:
|
||||
nsFontMetricsGTK();
|
||||
virtual ~nsFontMetricsGTK();
|
||||
|
||||
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(const nsFont& aFont, nsIAtom* aLangGroup,
|
||||
nsIDeviceContext* aContext);
|
||||
NS_IMETHOD Destroy();
|
||||
|
||||
NS_IMETHOD GetXHeight(nscoord& aResult);
|
||||
NS_IMETHOD GetSuperscriptOffset(nscoord& aResult);
|
||||
NS_IMETHOD GetSubscriptOffset(nscoord& aResult);
|
||||
NS_IMETHOD GetStrikeout(nscoord& aOffset, nscoord& aSize);
|
||||
NS_IMETHOD GetUnderline(nscoord& aOffset, nscoord& aSize);
|
||||
|
||||
NS_IMETHOD GetHeight(nscoord &aHeight);
|
||||
NS_IMETHOD GetNormalLineHeight(nscoord &aHeight);
|
||||
NS_IMETHOD GetLeading(nscoord &aLeading);
|
||||
NS_IMETHOD GetEmHeight(nscoord &aHeight);
|
||||
NS_IMETHOD GetEmAscent(nscoord &aAscent);
|
||||
NS_IMETHOD GetEmDescent(nscoord &aDescent);
|
||||
NS_IMETHOD GetMaxHeight(nscoord &aHeight);
|
||||
NS_IMETHOD GetMaxAscent(nscoord &aAscent);
|
||||
NS_IMETHOD GetMaxDescent(nscoord &aDescent);
|
||||
NS_IMETHOD GetMaxAdvance(nscoord &aAdvance);
|
||||
NS_IMETHOD GetFont(const nsFont *&aFont);
|
||||
NS_IMETHOD GetLangGroup(nsIAtom** aLangGroup);
|
||||
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
||||
|
||||
virtual nsresult GetSpaceWidth(nscoord &aSpaceWidth);
|
||||
|
||||
nsFontGTK* FindFont(PRUnichar aChar);
|
||||
nsFontGTK* FindUserDefinedFont(PRUnichar aChar);
|
||||
nsFontGTK* FindStyleSheetSpecificFont(PRUnichar aChar);
|
||||
nsFontGTK* FindStyleSheetGenericFont(PRUnichar aChar);
|
||||
nsFontGTK* FindLangGroupPrefFont(nsIAtom* aLangGroup, PRUnichar aChar);
|
||||
nsFontGTK* FindLangGroupFont(nsIAtom* aLangGroup, PRUnichar aChar, nsCString* aName);
|
||||
nsFontGTK* FindAnyFont(PRUnichar aChar);
|
||||
nsFontGTK* FindSubstituteFont(PRUnichar aChar);
|
||||
|
||||
nsFontGTK* SearchNode(nsFontNode* aNode, PRUnichar aChar);
|
||||
nsFontGTK* TryAliases(nsCString* aName, PRUnichar aChar);
|
||||
nsFontGTK* TryFamily(nsCString* aName, PRUnichar aChar);
|
||||
nsFontGTK* TryNode(nsCString* aName, PRUnichar aChar);
|
||||
nsFontGTK* TryNodes(nsAWritableCString &aFFREName, PRUnichar aChar);
|
||||
nsFontGTK* TryLangGroup(nsIAtom* aLangGroup, nsCString* aName, PRUnichar aChar);
|
||||
|
||||
nsFontGTK* AddToLoadedFontsList(nsFontGTK* aFont);
|
||||
nsFontGTK* PickASizeAndLoad(nsFontStretch* aStretch,
|
||||
nsFontCharSetInfo* aCharSet,
|
||||
PRUnichar aChar,
|
||||
const char *aName);
|
||||
|
||||
static nsresult FamilyExists(const nsString& aFontName);
|
||||
|
||||
//friend struct nsFontGTK;
|
||||
|
||||
nsFontGTK **mLoadedFonts;
|
||||
PRUint16 mLoadedFontsAlloc;
|
||||
PRUint16 mLoadedFontsCount;
|
||||
|
||||
nsFontGTK *mSubstituteFont;
|
||||
|
||||
nsCStringArray mFonts;
|
||||
PRUint16 mFontsIndex;
|
||||
nsVoidArray mFontIsGeneric;
|
||||
|
||||
nsCAutoString mDefaultFont;
|
||||
nsCString *mGeneric;
|
||||
nsCOMPtr<nsIAtom> mLangGroup;
|
||||
nsCAutoString mUserDefined;
|
||||
|
||||
PRUint8 mTriedAllGenerics;
|
||||
PRUint8 mIsUserDefined;
|
||||
|
||||
protected:
|
||||
void RealizeFont();
|
||||
|
||||
nsIDeviceContext *mDeviceContext;
|
||||
nsFont *mFont;
|
||||
nsFontGTK *mWesternFont;
|
||||
|
||||
nscoord mLeading;
|
||||
nscoord mEmHeight;
|
||||
nscoord mEmAscent;
|
||||
nscoord mEmDescent;
|
||||
nscoord mMaxHeight;
|
||||
nscoord mMaxAscent;
|
||||
nscoord mMaxDescent;
|
||||
nscoord mMaxAdvance;
|
||||
nscoord mXHeight;
|
||||
nscoord mSuperscriptOffset;
|
||||
nscoord mSubscriptOffset;
|
||||
nscoord mStrikeoutSize;
|
||||
nscoord mStrikeoutOffset;
|
||||
nscoord mUnderlineSize;
|
||||
nscoord mUnderlineOffset;
|
||||
nscoord mSpaceWidth;
|
||||
|
||||
PRUint16 mPixelSize;
|
||||
PRUint8 mStretchIndex;
|
||||
PRUint8 mStyleIndex;
|
||||
nsFontCharSetConverter mDocConverterType;
|
||||
};
|
||||
|
||||
class nsFontEnumeratorGTK : public nsIFontEnumerator
|
||||
{
|
||||
public:
|
||||
nsFontEnumeratorGTK();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFONTENUMERATOR
|
||||
};
|
||||
|
||||
#endif
|
||||
102
mozilla/webtools/leak-o-matic/Zip.pm
Normal file
102
mozilla/webtools/leak-o-matic/Zip.pm
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: Zip.pm,v 1.3 1999-11-17 19:15:00 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# Simple, incomplete interface to .zip files.
|
||||
#
|
||||
|
||||
|
||||
package Zip;
|
||||
|
||||
require 5.000;
|
||||
|
||||
use strict;
|
||||
|
||||
use Carp;
|
||||
use IO;
|
||||
use Symbol;
|
||||
use Time::Local;
|
||||
|
||||
my $zipname;
|
||||
|
||||
sub new($$) {
|
||||
@_ == 2 || croak 'usage: new Zip [FILENAME]';
|
||||
my $class = shift;
|
||||
my $zip = gensym;
|
||||
if (@_) {
|
||||
Zip::open($zip, $_[0]) || return undef;
|
||||
}
|
||||
bless $zip, $class;
|
||||
}
|
||||
|
||||
sub DESTROY($) {
|
||||
}
|
||||
|
||||
sub open($$) {
|
||||
@_ == 2 || croak 'usage: $zip->open(FILENAME)';
|
||||
my ($zip, $filename) = @_;
|
||||
$zipname = $filename;
|
||||
}
|
||||
|
||||
sub close($) {
|
||||
@_ == 1 || croak 'usage: $zip->close()';
|
||||
$zipname = undef;
|
||||
}
|
||||
|
||||
sub dir($) {
|
||||
@_ == 1 || croak 'usage: $zip->dir()';
|
||||
$zipname || croak 'no open zipfile';
|
||||
|
||||
|
||||
my @result = ();
|
||||
|
||||
my @list = qx/unzip -l $zipname/;
|
||||
ENTRY: foreach (@list) {
|
||||
# Entry expected to be in the format
|
||||
# size mm-dd-yy hh:mm name
|
||||
next ENTRY unless (/ *(\d+) +(\d+)-(\d+)-(\d+) +(\d+):(\d+) +(.+)$/);
|
||||
|
||||
my $mtime = Time::Local::timelocal(0, $6, $5, $3, $2, ($4 < 1900) ? ($4 + 1900) : $4);
|
||||
|
||||
push(@result, { name => $7,
|
||||
size => $1,
|
||||
mtime => $mtime });
|
||||
}
|
||||
|
||||
return @result;
|
||||
}
|
||||
|
||||
sub expand($$) {
|
||||
@_ == 2 || croak 'usage: $zip->expand(FILENAME)';
|
||||
$zipname || croak 'no open zipfile';
|
||||
|
||||
my $filename = $_[1];
|
||||
|
||||
my $result = new IO::Handle;
|
||||
CORE::open($result, "unzip -p $zipname $filename |");
|
||||
return $result;
|
||||
}
|
||||
|
||||
1;
|
||||
366
mozilla/webtools/leak-o-matic/balance.cgi
Executable file
366
mozilla/webtools/leak-o-matic/balance.cgi
Executable file
@@ -0,0 +1,366 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: balance.cgi,v 1.2 1999-11-17 19:15:00 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# Builds a tree of reference counts
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
|
||||
use CGI;
|
||||
use POSIX;
|
||||
use Zip;
|
||||
|
||||
$::query = new CGI();
|
||||
|
||||
$::opt_log = $::query->param('log');
|
||||
$::opt_class = $::query->param('class');
|
||||
$::opt_object = $::query->param('object');
|
||||
@::opt_exclude = $::query->param('exclude');
|
||||
$::opt_show_balanced = $::query->param('show-balanced');
|
||||
$::opt_subtree_size = $::query->param('subtree-size');
|
||||
$::opt_prune_depth = $::query->param('prune-depth');
|
||||
$::opt_reverse = $::query->param('reverse');
|
||||
$::opt_collapse_to_method = $::query->param('collapse-to-method');
|
||||
$::opt_collapse_to_class = $::query->param('collapse-to-class');
|
||||
|
||||
$::opt_log || die;
|
||||
$::opt_class || die;
|
||||
$::opt_object || die;
|
||||
|
||||
# Make sure that values get initialized properly
|
||||
$::opt_prune_depth = 0 if (! $::opt_prune_depth);
|
||||
$::opt_subtree_size = 0 if (! $::opt_subtree_size);
|
||||
$::opt_collapse_to_class = 0 if (! $::opt_collapse_to_class);
|
||||
$::opt_collapse_to_method = 0 if (! $::opt_collapse_to_method);
|
||||
|
||||
# Sanity checks
|
||||
$::opt_prune_depth = 0 if $::opt_prune_depth < 0;
|
||||
$::opt_subtree_size = 0 if $::opt_subtree_size < 0;
|
||||
|
||||
|
||||
print $::query->header;
|
||||
|
||||
print qq{
|
||||
<html>
|
||||
<head>
|
||||
<title>$::opt_class [$::opt_object]</title>
|
||||
<script language="JavaScript" src="balance.js"></script>
|
||||
<style type="text/css" src="balance.css"></style>
|
||||
</head>
|
||||
<body>
|
||||
};
|
||||
|
||||
print $::query->h1("$::opt_class [$::opt_object]");
|
||||
|
||||
print "<small>\n";
|
||||
{
|
||||
my @statinfo = stat($::opt_log);
|
||||
my $when = POSIX::strftime "%a %b %e %H:%M:%S %Y", localtime($statinfo[9]);
|
||||
print "$when<br>\n";
|
||||
}
|
||||
|
||||
print "<a href='bloat-log.cgi?log=$::opt_log'>Bloat Log</a>\n";
|
||||
print "<a href='leaks.cgi?log=$::opt_log'>Back to Overview</a>\n";
|
||||
print "</small>\n";
|
||||
|
||||
# The 'excludes' are functions that, if detected in a particular call
|
||||
# stack, will cause the _entire_ call stack to be ignored. You might,
|
||||
# for example, explicitly exclude two functions that have a matching
|
||||
# AddRef/Release pair.
|
||||
|
||||
my %excludes;
|
||||
{
|
||||
my $method;
|
||||
foreach $method (@::opt_exclude) {
|
||||
$excludes{$method} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Each entry in the tree rooted by callGraphRoot contains the following:
|
||||
# #name# This call's name+offset string
|
||||
# #refcount# The net reference count of this call
|
||||
# #label# The label used for this subtree; only defined for labeled nodes
|
||||
# #children# List of children in alphabetical order
|
||||
# zero or more children indexed by method name+offset strings.
|
||||
|
||||
my $callGraphRoot;
|
||||
$callGraphRoot = { '#name#' => '.root', '#refcount#' => 'n/a' };
|
||||
|
||||
# The 'imbalance' is a gross count of how balanced a particular
|
||||
# callsite is. It is used to prune away callsites that are detected to
|
||||
# be balanced; that is, that have matching AddRef/Release() pairs.
|
||||
|
||||
my %imbalance;
|
||||
$imbalance{'.root'} = 'n/a';
|
||||
|
||||
|
||||
# The main read loop.
|
||||
my $log = new Zip($::opt_log);
|
||||
$log || die('unable to open log $log');
|
||||
|
||||
my $logfile = "refcnt-" . $::opt_class . "-" . $::opt_object . ".log";
|
||||
|
||||
my $handle = $log->expand($logfile);
|
||||
|
||||
LINE: while (<$handle>) {
|
||||
next LINE if (! /^</);
|
||||
my @fields = split(/ /, $_);
|
||||
|
||||
my $class = shift(@fields);
|
||||
my $obj = shift(@fields);
|
||||
my $sno = shift(@fields);
|
||||
next LINE unless ($sno eq $::opt_object);
|
||||
|
||||
my $op = shift(@fields);
|
||||
next LINE unless ($op eq "AddRef" || $op eq "Release");
|
||||
|
||||
my $cnt = shift(@fields);
|
||||
|
||||
# Collect the remaining lines to create a stack trace.
|
||||
my @stack;
|
||||
CALLSITE: while (<$handle>) {
|
||||
chomp;
|
||||
last CALLSITE if (/^$/);
|
||||
$stack[++$#stack] = $_;
|
||||
}
|
||||
|
||||
# Reverse the remaining fields to produce the call stack, with the
|
||||
# oldest frame at the front of the array.
|
||||
if (! $::opt_reverse) {
|
||||
@stack = reverse(@stack);
|
||||
}
|
||||
|
||||
my $call;
|
||||
|
||||
# If any of the functions in the stack are supposed to be excluded,
|
||||
# march on to the next line.
|
||||
foreach $call (@stack) {
|
||||
next LINE if exists($excludes{$call});
|
||||
}
|
||||
|
||||
|
||||
# Add the callstack as a path through the call graph, updating
|
||||
# refcounts at each node.
|
||||
|
||||
my $caller = $callGraphRoot;
|
||||
|
||||
foreach $call (@stack) {
|
||||
|
||||
# Chop the method offset if we're 'collapsing to method' or
|
||||
# 'collapsing to class'.
|
||||
$call =~ s/\+0x.*$//g if ($::opt_collapse_to_method || $::opt_collapse_to_class);
|
||||
|
||||
# Chop the method name if we're 'collapsing to class'.
|
||||
$call =~ s/::.*$//g if ($::opt_collapse_to_class);
|
||||
|
||||
my $site = $caller->{$call};
|
||||
if (!$site) {
|
||||
# This is the first time we've seen this callsite. Add a
|
||||
# new entry to the call tree.
|
||||
|
||||
$site = { '#name#' => $call, '#refcount#' => 0 };
|
||||
$caller->{$call} = $site;
|
||||
}
|
||||
|
||||
if ($op eq 'AddRef') {
|
||||
++($site->{'#refcount#'});
|
||||
++($imbalance{$call});
|
||||
} elsif ($op eq 'Release') {
|
||||
--($site->{'#refcount#'});
|
||||
--($imbalance{$call});
|
||||
} else {
|
||||
die "Bad operation $op";
|
||||
}
|
||||
|
||||
$caller = $site;
|
||||
}
|
||||
}
|
||||
|
||||
# Given a subtree and its nesting level, return true if that subtree should be pruned.
|
||||
# If it shouldn't be pruned, destructively attempt to prune its children.
|
||||
# Also compute the #children# properties of unpruned nodes.
|
||||
sub prune($$) {
|
||||
my ($site, $nest) = @_;
|
||||
|
||||
# If they want us to prune the tree's depth, do so here.
|
||||
return 1 if ($::opt_prune_depth && $nest >= $::opt_prune_depth);
|
||||
|
||||
# If the subtree is balanced, ignore it.
|
||||
return 1 if (!$::opt_show_balanced && !$site->{'#refcount#'});
|
||||
|
||||
my $name = $site->{'#name#'};
|
||||
|
||||
# If the symbol isn't imbalanced, then prune here (and warn)
|
||||
# XXX no symbol-level balancing; this was buggy.
|
||||
# if (!$::opt_show_balanced && !$imbalance{$name}) {
|
||||
# warn "discarding " . $name . "\n";
|
||||
# return 1;
|
||||
# }
|
||||
|
||||
my @children;
|
||||
foreach my $child (sort(keys(%$site))) {
|
||||
if (substr($child, 0, 1) ne '#') {
|
||||
if (prune($site->{$child}, $nest + 1)) {
|
||||
delete $site->{$child};
|
||||
} else {
|
||||
push @children, $site->{$child};
|
||||
}
|
||||
}
|
||||
}
|
||||
$site->{'#children#'} = \@children;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
# Compute the #label# properties of this subtree.
|
||||
# Return the subtree's number of nodes, not counting nodes reachable
|
||||
# through a labeled node.
|
||||
sub createLabels($) {
|
||||
my ($site) = @_;
|
||||
my @children = @{$site->{'#children#'}};
|
||||
my $nChildren = @children;
|
||||
my $nDescendants = 0;
|
||||
|
||||
foreach my $child (@children) {
|
||||
my $childDescendants = createLabels($child);
|
||||
if ($nChildren > 1 && $childDescendants > $::opt_subtree_size) {
|
||||
die "Internal error" if defined($child->{'#label#'});
|
||||
$child->{'#label#'} = "__label__";
|
||||
$childDescendants = 1;
|
||||
}
|
||||
$nDescendants += $childDescendants;
|
||||
}
|
||||
return $nDescendants + 1;
|
||||
}
|
||||
|
||||
|
||||
my $nextLabel = 0;
|
||||
my @labeledSubtrees;
|
||||
|
||||
sub list($$$$$) {
|
||||
my ($site, $nest, $nestStr, $childrenLeft, $root) = @_;
|
||||
my $label = !$root && $site->{'#label#'};
|
||||
|
||||
# Assign a unique number to the label.
|
||||
if ($label) {
|
||||
die unless $label eq "__label__";
|
||||
$label = "__" . ++$nextLabel . "__";
|
||||
$site->{'#label#'} = $label;
|
||||
push @labeledSubtrees, $site;
|
||||
}
|
||||
|
||||
print $nestStr;
|
||||
if ($::opt_old_style) {
|
||||
print $label, " " if $label;
|
||||
print $site->{'#name#'}, ": bal=", $site->{'#refcount#'}, "\n";
|
||||
} else {
|
||||
my $refcount = $site->{'#refcount#'};
|
||||
my $l = 8 - length $refcount;
|
||||
$l = 1 if $l < 1;
|
||||
print $refcount, " " x $l;
|
||||
print $label, " " if $label;
|
||||
print "<tt class='method'>";
|
||||
print $site->{'#name#'};
|
||||
print "</tt>\n";
|
||||
}
|
||||
|
||||
$nestStr .= $childrenLeft && !$::opt_old_style ? "| " : " ";
|
||||
if (!$label) {
|
||||
my @children = @{$site->{'#children#'}};
|
||||
$childrenLeft = @children;
|
||||
foreach my $child (@children) {
|
||||
$childrenLeft--;
|
||||
list($child, $nest + 1, $nestStr, $childrenLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!prune($callGraphRoot, 0)) {
|
||||
createLabels $callGraphRoot if ($::opt_subtree_size);
|
||||
|
||||
print "<div onclick='toggle(event.target);'><pre>\n";
|
||||
list $callGraphRoot, 0, "", 0, 1;
|
||||
while (@labeledSubtrees) {
|
||||
my $labeledSubtree = shift @labeledSubtrees;
|
||||
print "\n<hr>\n", $labeledSubtree->{'#label#'}, "\n";
|
||||
list $labeledSubtree, 0, "", 0, 1;
|
||||
}
|
||||
print "\n<hr>\n" if @labeledSubtrees;
|
||||
print "</pre></div>\n";
|
||||
}
|
||||
|
||||
# Now generate the control panel at the bottom. This needs to be "neater".
|
||||
|
||||
print qq{
|
||||
<hr>
|
||||
<form method='get' action='balance.cgi' onsubmit='onsubmit();'>
|
||||
<input id='log' name='log' type='hidden' value='$::opt_log'></input>
|
||||
<input id='class' name='class' type='hidden' value='$::opt_class'></input>
|
||||
<input id='object' name='object' type='hidden' value='$::opt_object'></input>
|
||||
|
||||
<fieldset>
|
||||
<legend>Methods to Exclude</legend>
|
||||
<select id='exclude' name='exclude' style='width:100%;height:10em' size="10" multiple>
|
||||
};
|
||||
|
||||
{
|
||||
my $method;
|
||||
foreach $method (@::opt_exclude) {
|
||||
print " <option selected>$method</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print qq{
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<input type="button" onclick="remove();" value="Remove"></input>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Options</legend>
|
||||
};
|
||||
|
||||
print "<input id='collapse-to-method' name='collapse-to-method' type='checkbox' value='$::opt_collapse_to_method' ";
|
||||
print "checked" if $::opt_collapse_to_method;
|
||||
print ">Collapse To Method</input>\n";
|
||||
|
||||
print "<input id='collapse-to-class' value='collapse-to-class' type='checkbox' value='$::opt_collapse_to_class' ";
|
||||
print "checked" if $::opt_collapse_to_class;
|
||||
print ">Collapse To Class</input>\n";
|
||||
|
||||
print qq{
|
||||
</fieldset>
|
||||
|
||||
<input type='submit' value='Rebuild'></input>
|
||||
</form>
|
||||
};
|
||||
|
||||
print $::query->end_html;
|
||||
|
||||
|
||||
38
mozilla/webtools/leak-o-matic/balance.css
Normal file
38
mozilla/webtools/leak-o-matic/balance.css
Normal file
@@ -0,0 +1,38 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Leak-o-Matic.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corp. Portions created by Netscape Communucations
|
||||
* Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*
|
||||
* $Id: balance.css,v 1.2 1999-11-17 19:15:01 waterson%netscape.com Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Style rules for the HTML generated by ``balance.cgi''
|
||||
|
||||
*/
|
||||
|
||||
tt.method {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
tt.method[selected ~= "true"] {
|
||||
color: red;
|
||||
}
|
||||
97
mozilla/webtools/leak-o-matic/balance.js
Normal file
97
mozilla/webtools/leak-o-matic/balance.js
Normal file
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Leak-o-Matic.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corp. Portions created by Netscape Communucations
|
||||
* Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*
|
||||
* $Id: balance.js,v 1.2 1999-11-17 19:15:02 waterson%netscape.com Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Script for the HTML generated by ``balance.cgi''
|
||||
|
||||
*/
|
||||
|
||||
function toggle(target)
|
||||
{
|
||||
var tt = target.parentNode;
|
||||
|
||||
// ensure that we're actuallly looking at a method
|
||||
if (tt.getAttribute('class') != 'method') return;
|
||||
|
||||
// toggle the selected state
|
||||
var selected = tt.getAttribute('selected') == 'true';
|
||||
selected = !selected;
|
||||
tt.setAttribute('selected', selected ? 'true' : 'false');
|
||||
|
||||
// add/remove from the 'exclude' list
|
||||
var exclude = document.getElementById('exclude');
|
||||
var value = target.nodeValue;
|
||||
|
||||
if (selected) {
|
||||
var found = false;
|
||||
for (var i = 0; i < exclude.length; ++i) {
|
||||
if (exclude.options[i].text == value) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! found) {
|
||||
dump('adding ' + value + '\n');
|
||||
var option = document.createElement('option');
|
||||
option.setAttribute('selected', 'true');
|
||||
option.appendChild(document.createTextNode(value));
|
||||
exclude.appendChild(option);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < exclude.length; ++i) {
|
||||
if (exclude.options[i].text == value) {
|
||||
exclude.removeChild(exclude.options[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function remove() {
|
||||
// remove all of the selected items from the 'exclude' list
|
||||
var exclude = document.getElementById('exclude');
|
||||
|
||||
for (var i = 0; i < exclude.length; ++i) {
|
||||
if (exclude.options[i].selected) {
|
||||
exclude.removeChild(exclude.options[i]);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onsubmit() {
|
||||
// make sure that all of the elements in the select are actually
|
||||
// -selected- so that the HTTP GET will contain them as excludes.
|
||||
var exclude = document.getElementById('exclude');
|
||||
|
||||
for (var i = 0; i < exclude.length; ++i) {
|
||||
// XXX doing this with 'options[i].selected = true' actually
|
||||
// -changes- the selection. Oops.
|
||||
exclude.options[i].setAttribute('selected', 'true');
|
||||
}
|
||||
}
|
||||
65
mozilla/webtools/leak-o-matic/bloat-log.cgi
Executable file
65
mozilla/webtools/leak-o-matic/bloat-log.cgi
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: bloat-log.cgi,v 1.3 1999-11-17 19:15:02 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# Extracts the original bloat log from a Leak-o-Matic zip
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use CGI;
|
||||
use POSIX;
|
||||
use Zip;
|
||||
|
||||
$::query = new CGI();
|
||||
|
||||
# The ZIP where all the log files are kept
|
||||
$::log = $::query->param('log');
|
||||
$::zip = new Zip($::log);
|
||||
|
||||
print $::query->header;
|
||||
|
||||
{
|
||||
my @statinfo = stat($::log);
|
||||
my $when = POSIX::strftime "%a %b %e %H:%M:%S %Y", localtime($statinfo[9]);
|
||||
|
||||
print $::query->start_html("Bloat Log, $when"),
|
||||
$::query->h1("Bloat Log");
|
||||
|
||||
print "<small>$when</small>\n";
|
||||
}
|
||||
|
||||
print "<pre>\n";
|
||||
|
||||
{
|
||||
my $handle = $::zip->expand('master-bloat.log');
|
||||
|
||||
while (<$handle>) {
|
||||
print $_;
|
||||
}
|
||||
}
|
||||
|
||||
print "</pre>\n";
|
||||
print $::query->end_html;
|
||||
73
mozilla/webtools/leak-o-matic/handle-mail.pl
Executable file
73
mozilla/webtools/leak-o-matic/handle-mail.pl
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: handle-mail.pl,v 1.4 1999-11-18 03:38:24 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# ``sendmail'' handler to receive data on the server. Cooperates with
|
||||
# ``make-data.pl'', the data collection script.
|
||||
#
|
||||
# To use, create an account on your server; e.g., "leak-o-matic", that
|
||||
# will receive mail from the data collector. In this account's home
|
||||
# directory, create a .forward file that containes the following
|
||||
#
|
||||
# "|handle-mail.pl --datadir=whatever"
|
||||
#
|
||||
# Yes, the quotes are important. Depending on your sendmail
|
||||
# configuration, you may need to place the ``handle-mail.pl'' script
|
||||
# in a special directory; e.g., /etc/smrsh on a vanilla RH6.0 system.
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use File::Copy;
|
||||
|
||||
GetOptions("datadir=s");
|
||||
chdir('/tmp');
|
||||
|
||||
# Open a pipe to ``uudecode'' so we can unstuff the binary
|
||||
open(OUT, "|uudecode");
|
||||
|
||||
LINE: while (<>) {
|
||||
# Ignore anything up until the ``begin'' directive
|
||||
if (/^begin \d\d\d (.*)/) {
|
||||
$::file = $1;
|
||||
print OUT $_;
|
||||
last LINE;
|
||||
}
|
||||
}
|
||||
|
||||
# No file means we read the entire message and found nothing
|
||||
$::file || die;
|
||||
|
||||
while (<>) {
|
||||
print OUT $_;
|
||||
}
|
||||
|
||||
# Be sure to close the pipe (so uudecode can complete) before moving
|
||||
# the file
|
||||
close(OUT);
|
||||
|
||||
# Move to the data directory, if there is one.
|
||||
move($::file, $::opt_datadir) if $::opt_datadir;
|
||||
23
mozilla/webtools/leak-o-matic/instructions.html
Normal file
23
mozilla/webtools/leak-o-matic/instructions.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Leak-o-Matic Instructions</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td bgcolor="#000000" valign="top">
|
||||
<img src="http://www.mozilla.org/images/mozilla-banner.gif"
|
||||
alt="mozilla.org" border="0" href="http://www.mozilla.org/">
|
||||
</td></tr></table>
|
||||
|
||||
<center>
|
||||
<h1>Leak-o-Matic Instructions</h1>
|
||||
</center>
|
||||
|
||||
<p>
|
||||
Write me!
|
||||
</p>
|
||||
|
||||
<small>$Id: instructions.html,v 1.1 1999-11-16 22:10:08 waterson%netscape.com Exp $</small>
|
||||
</body>
|
||||
</html>
|
||||
103
mozilla/webtools/leak-o-matic/leaks.cgi
Executable file
103
mozilla/webtools/leak-o-matic/leaks.cgi
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: leaks.cgi,v 1.3 1999-11-17 19:15:03 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# Expands a logfile into all of the leakers
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use CGI;
|
||||
use POSIX;
|
||||
use Zip;
|
||||
|
||||
$::query = new CGI();
|
||||
|
||||
# The ZIP where all the log files are kept
|
||||
$::log = $::query->param('log');
|
||||
$::zip = new Zip($::log);
|
||||
|
||||
print $::query->header;
|
||||
|
||||
{
|
||||
my @statinfo = stat($::log);
|
||||
my $when = POSIX::strftime "%a %b %e %H:%M:%S %Y", localtime($statinfo[9]);
|
||||
|
||||
print $::query->start_html("Leaked Objects, $when"),
|
||||
$::query->h1("Leaked Objects");
|
||||
|
||||
print "<small>$when<br><a href='bloat-log.cgi?log=$::log'>Bloat Log</a></small>\n";
|
||||
}
|
||||
|
||||
# Collect all of the log files. Files are assumed to be named
|
||||
# "refcnt-class-serialno.log", so we'll list all of the files and then
|
||||
# parse out the 'class' and 'serialno' values to present a pretty
|
||||
# HTML-ized version.
|
||||
{
|
||||
my @files = $::zip->dir();
|
||||
|
||||
my $current = "";
|
||||
my $count = 0;
|
||||
|
||||
my $file;
|
||||
FILE: foreach (@files) {
|
||||
$_ = $$_{name};
|
||||
next FILE unless (/^refcnt-([^-]+)-(\d+).log$/);
|
||||
|
||||
$::classes{$1} = [] if !$::classes{$1};
|
||||
my $objects = $::classes{$1};
|
||||
push(@$objects, $2);
|
||||
}
|
||||
}
|
||||
|
||||
print "<table border='0'>\n";
|
||||
print "<th><tr bgcolor='#DDDDDD'><td align='center'><b>Class</b></td><td align='center'><b>Objects</b></td></tr></th>\n";
|
||||
print "<tbody>\n";
|
||||
|
||||
{
|
||||
my $bgcolor='#FFFFFF';
|
||||
|
||||
my $class;
|
||||
foreach $class (sort(keys(%::classes))) {
|
||||
print "<tr bgcolor='$bgcolor'>\n";
|
||||
print "<td valign='top'><a href='http://lxr.mozilla.org/seamonkey/ident?i=$class'>$class</a></td>\n";
|
||||
print "<td><small>\n";
|
||||
my $objects = $::classes{$class};
|
||||
|
||||
my $object;
|
||||
foreach $object (sort { $::a <=> $::b } @$objects) {
|
||||
print "<a href='balance.cgi?log=$::log&class=$class&object=$object'>$object</a>\n";
|
||||
}
|
||||
print "\n</small></td>\n";
|
||||
print "</tr>\n";
|
||||
|
||||
$bgcolor = ($bgcolor eq '#FFFFFF') ? '#FFFFBB' : '#FFFFFF';
|
||||
}
|
||||
}
|
||||
|
||||
print "</tbody></table>\n";
|
||||
|
||||
print $::query->end_html;
|
||||
|
||||
101
mozilla/webtools/leak-o-matic/logs.cgi
Executable file
101
mozilla/webtools/leak-o-matic/logs.cgi
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Testing 1-2-3
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: logs.cgi,v 1.6.2.1 2000-01-07 03:46:25 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# ``Front door'' script that shows all of the logs that are
|
||||
# available for perusal
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use CGI;
|
||||
use POSIX;
|
||||
|
||||
$::query = new CGI();
|
||||
$::logdir = $::query->param('logdir');
|
||||
$::logdir = 'data' unless $::logdir; # default is 'data' subdir
|
||||
|
||||
print $::query->header;
|
||||
print $::query->start_html("Leak-o-Matic");
|
||||
|
||||
print qq{
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
||||
<tr>
|
||||
<td bgcolor='#000000' valign='top'>
|
||||
<img src='http://www.mozilla.org/images/mozilla-banner.gif'
|
||||
border="0" alt='mozilla.org' href='http://www.mozilla.org/'>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<center>
|
||||
<h1>Leak-o-Matic</h1>
|
||||
</center>
|
||||
|
||||
<p>
|
||||
Welcome to the Marvelous Leak-o-Matic. Listed below are the leak logs
|
||||
that are currently available for your perusal.
|
||||
</p>
|
||||
|
||||
<div align='center'>
|
||||
<table border='0' cellpadding='2' cellspacing='0' bgcolor='#EEEEEE'>
|
||||
<tr><td bgcolor='#DDDDDD' align='center' colspan='3'><b>Leak-o-Matic Logs</b></td></tr>
|
||||
|
||||
};
|
||||
|
||||
# ``ls'' the directory, ``-1r'' returns it sorted by name, reversed, so
|
||||
# the most recent logs will be at the top.
|
||||
|
||||
ZIP: foreach (qx/ls -1r $::logdir\/*.zip/) {
|
||||
chomp;
|
||||
|
||||
next ZIP unless (/(\d\d\d\d)(\d\d)(\d\d)/);
|
||||
|
||||
my ($year, $month, $day) = ($1, $2, $3);
|
||||
|
||||
print "<tr>\n";
|
||||
print "<td>$month/$day/$year</td>\n";
|
||||
print "<td><a href='leaks.cgi?log=$_'>Leaks</a></td>\n";
|
||||
print "<td><a href='bloat-log.cgi?log=$_'>Bloat Log</a></td>\n";
|
||||
print "</tr>\n";
|
||||
}
|
||||
|
||||
print qq{
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
For more information on how to use the Leak-o-Matic, see the
|
||||
|
||||
<a href="instructions.html">instructions</a>.
|
||||
</p>
|
||||
|
||||
};
|
||||
|
||||
print '<small>$Id: logs.cgi,v 1.6.2.1 2000-01-07 03:46:25 waterson%netscape.com Exp $</small>';
|
||||
print $::query->end_html;
|
||||
|
||||
177
mozilla/webtools/leak-o-matic/make-data.pl
Executable file
177
mozilla/webtools/leak-o-matic/make-data.pl
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is Mozilla Leak-o-Matic.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corp. Portions created by Netscape Communucations
|
||||
# Corp. are Copyright (C) 1999 Netscape Communications Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Chris Waterson <waterson@netscape.com>
|
||||
#
|
||||
# $Id: make-data.pl,v 1.6 1999-11-18 06:06:28 waterson%netscape.com Exp $
|
||||
#
|
||||
|
||||
#
|
||||
# This script runs the apecified application until it's blue in the
|
||||
# face. First, it runs it to generate a top level ``master bloat''
|
||||
# log, containing a map of all the objects leaked. For each class that
|
||||
# it detects has leaked, it re-runs the app to collect the serial
|
||||
# numbers of the objects leaked. Then for each object, it re-runs the
|
||||
# app to collect a stack trace.
|
||||
#
|
||||
# It creates a ``.zip'' file that is meant to be used with
|
||||
# ``logs.cgi'' and the rest of the Leak-o-Matic CGIs. If the
|
||||
# ``--email'' option is specified, it will mail the ``.zip'' file,
|
||||
# uuencoded, to the specified address. See ``handle-mail.pl'' for a
|
||||
# server-side mail handler.
|
||||
#
|
||||
|
||||
use 5.004;
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use POSIX "sys_wait_h";
|
||||
|
||||
$::opt_dir = ".";
|
||||
$::opt_app = "mozilla-bin -f bloaturls.txt";
|
||||
$::opt_timeout = 600;
|
||||
|
||||
GetOptions("dir=s", "app=s", "email=s", "timeout=i");
|
||||
|
||||
sub ForkAndWait($$$) {
|
||||
my ($dir, $app, $timeout) = @_;
|
||||
my $pid = fork;
|
||||
|
||||
if ($pid == 0) {
|
||||
open(STDOUT, ">/dev/null");
|
||||
open(STDERR, ">/dev/null");
|
||||
chdir($::opt_dir);
|
||||
exec("$app");
|
||||
# bye!
|
||||
}
|
||||
|
||||
if ($timeout > 0) {
|
||||
while ($timeout--) {
|
||||
sleep 1;
|
||||
my $status = POSIX::waitpid($pid, WNOHANG());
|
||||
return 0 if $status != 0;
|
||||
}
|
||||
|
||||
kill("TERM", $pid);
|
||||
POSIX::waitpid($pid, 0);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
POSIX::waitpid($pid, 0);
|
||||
}
|
||||
|
||||
my $status = $? / 256;
|
||||
if ($status != 0) {
|
||||
die "'$app' terminated abnormally, status == $status";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# First, just run the browser with the bloat log turned on. From that,
|
||||
# we'll capture all of the leaky classes.
|
||||
|
||||
my $MasterBloatLog = $ENV{"PWD"} . "/master-bloat.log";
|
||||
|
||||
printf("generating top-level class list\n");
|
||||
$ENV{"XPCOM_MEM_BLOAT_LOG"} = $MasterBloatLog;
|
||||
|
||||
ForkAndWait($::opt_dir, $::opt_app, 0);
|
||||
|
||||
# Now parse the bloat log.
|
||||
my @leakyclasses;
|
||||
|
||||
{
|
||||
open(BLOATLOG, $MasterBloatLog);
|
||||
|
||||
LINE: while (<BLOATLOG>) {
|
||||
s/^ +//;
|
||||
next LINE unless /^[0-9]/;
|
||||
|
||||
my ($num, $class, $bytesPerInst, $bytesLeaked,
|
||||
$totalObjects, $remainingObjects)
|
||||
= split(/ +/);
|
||||
|
||||
next LINE unless ($num > 0 && $remainingObjects > 0);
|
||||
|
||||
$leakyclasses[++$#leakyclasses] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
# Iterate through each class that leaked, and find out what objects
|
||||
# have leaked.
|
||||
|
||||
my $BloatLogFile = "/tmp/leak-report-bloat.log";
|
||||
$ENV{"XPCOM_MEM_BLOAT_LOG"} = $BloatLogFile;
|
||||
|
||||
my $class;
|
||||
foreach $class (@leakyclasses) {
|
||||
printf("+ $class\n");
|
||||
|
||||
delete $ENV{"XPCOM_MEM_REFCNT_LOG"};
|
||||
delete $ENV{"XPCOM_MEM_LOG_OBJECTS"};
|
||||
$ENV{"XPCOM_MEM_LOG_CLASSES"} = $class;
|
||||
|
||||
ForkAndWait($::opt_dir, $::opt_app, 0);
|
||||
|
||||
open(BLOATLOG, $BloatLogFile);
|
||||
|
||||
my @leakedobjects;
|
||||
my $serialNumbersHaveStarted = 0;
|
||||
|
||||
LINE: while (<BLOATLOG>) {
|
||||
$serialNumbersHaveStarted = 1
|
||||
if /^Serial Numbers of Leaked Objects:/;
|
||||
|
||||
next LINE unless ($serialNumbersHaveStarted && /^[0-9]/);
|
||||
|
||||
chomp;
|
||||
$leakedobjects[++$#leakedobjects] = $_;
|
||||
}
|
||||
|
||||
# ...and for each object that leaked, generate reference count
|
||||
# stack traces.
|
||||
|
||||
my $object;
|
||||
foreach $object (@leakedobjects) {
|
||||
my $refcntlogfile = $ENV{"PWD"} . "/refcnt-" . $class . "-" . $object . ".log";
|
||||
|
||||
print "|- $refcntlogfile\n";
|
||||
|
||||
$ENV{"XPCOM_MEM_REFCNT_LOG"} = $refcntlogfile;
|
||||
$ENV{"XPCOM_MEM_LOG_OBJECTS"} = $object;
|
||||
|
||||
if (ForkAndWait($::opt_dir, $::opt_app, $::opt_timeout) < 0) {
|
||||
print " * Timed out; discarding.\n";
|
||||
unlink $refcntlogfile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
# Now zip up all of the datafiles into YYYYMMDD.zip
|
||||
my $zipfile = POSIX::strftime("%Y%m%d.zip", localtime(time));
|
||||
system("zip -m $zipfile *.log");
|
||||
|
||||
# ...and mail it off to the server
|
||||
system("cat $zipfile | uuencode $zipfile | mail $::opt_email")
|
||||
if $::opt_email;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom
|
||||
XPIDL_MODULE = xpcom_ds
|
||||
LIBRARY_NAME = xpcomds_s
|
||||
REQUIRES = unicharutil string
|
||||
|
||||
CSRCS = \
|
||||
pldhash.c \
|
||||
plvector.c \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsArena.cpp \
|
||||
nsAtomTable.cpp \
|
||||
nsAtomService.cpp \
|
||||
nsAVLTree.cpp \
|
||||
nsByteBuffer.cpp \
|
||||
nsCRT.cpp \
|
||||
nsConjoiningEnumerator.cpp \
|
||||
nsDeque.cpp \
|
||||
nsEmptyEnumerator.cpp \
|
||||
nsEnumeratorUtils.cpp \
|
||||
nsFixedSizeAllocator.cpp \
|
||||
nsHashtable.cpp \
|
||||
nsHashtableEnumerator.cpp \
|
||||
nsObserver.cpp \
|
||||
nsObserverList.cpp \
|
||||
nsObserverService.cpp \
|
||||
nsProperties.cpp \
|
||||
nsPersistentProperties.cpp \
|
||||
nsQuickSort.cpp \
|
||||
nsSizeOfHandler.cpp \
|
||||
nsStaticNameTable.cpp \
|
||||
nsStatistics.cpp \
|
||||
nsStringMap.cpp \
|
||||
nsSupportsArray.cpp \
|
||||
nsSupportsArrayEnumerator.cpp \
|
||||
nsSupportsPrimitives.cpp \
|
||||
nsUnicharBuffer.cpp \
|
||||
nsVoidArray.cpp \
|
||||
nsVoidBTree.cpp \
|
||||
nsTextFormatter.cpp \
|
||||
nsTimelineService.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsAVLTree.h \
|
||||
nsAtomService.h \
|
||||
nsCppSharedAllocator.h \
|
||||
nsCRT.h \
|
||||
nsDeque.h \
|
||||
nsEnumeratorUtils.h \
|
||||
nsFixedSizeAllocator.h \
|
||||
nsHashtable.h \
|
||||
nsHashtableEnumerator.h \
|
||||
nsIArena.h \
|
||||
nsIByteBuffer.h \
|
||||
nsIObserverList.h \
|
||||
nsISimpleEnumerator.h \
|
||||
nsISizeOfHandler.h \
|
||||
nsIUnicharBuffer.h \
|
||||
nsInt64.h \
|
||||
nsQuickSort.h \
|
||||
nsStaticNameTable.h \
|
||||
nsStatistics.h \
|
||||
nsStringMap.h \
|
||||
nsSupportsArray.h \
|
||||
nsSupportsPrimitives.h \
|
||||
nsTime.h \
|
||||
nsUnitConversion.h \
|
||||
nsVector.h \
|
||||
nsVoidArray.h \
|
||||
nsVoidBTree.h \
|
||||
pldhash.h \
|
||||
plvector.h \
|
||||
nsTextFormatter.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIAtom.idl \
|
||||
nsIAtomService.idl \
|
||||
nsICollection.idl \
|
||||
nsIEnumerator.idl \
|
||||
nsIObserver.idl \
|
||||
nsIObserverService.idl \
|
||||
nsIPersistentProperties2.idl \
|
||||
nsIProperties.idl \
|
||||
nsISerializable.idl \
|
||||
nsIStopwatch.idl \
|
||||
nsISupportsArray.idl \
|
||||
nsISupportsIterators.idl \
|
||||
nsISupportsPrimitives.idl \
|
||||
nsITimelineService.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a static lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
# Force use of PIC
|
||||
FORCE_USE_PIC = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is James L. Nance
|
||||
* Portions created by James L. Nance are Copyright (C) 2001
|
||||
* James L. Nance. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Patricia Jewell Nance, Jesse Jacob Nance
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
// #define TEST_PATRICIA
|
||||
|
||||
#if defined(TEST_PATRICIA)
|
||||
# include "stdlib.h"
|
||||
# include "stdio.h"
|
||||
# include "string.h"
|
||||
# define PRBool bool
|
||||
# define PRUint32 unsigned int
|
||||
# define PRInt32 int
|
||||
# define PR_CALLBACK
|
||||
# define PLArenaPool int
|
||||
# define PL_FinishArenaPool(a)
|
||||
# define PL_InitArenaPool(a, b, c, d)
|
||||
# define PL_ArenaAllocate(a, size) malloc(size)
|
||||
# define PR_TRUE true
|
||||
# define PR_FALSE false
|
||||
|
||||
struct nsCRT {
|
||||
static int strlen(const char *a) {return ::strlen(a);}
|
||||
static int memcmp(const void *a, const void *b, PRUint32 c) {
|
||||
return ::memcmp(a,b,c);
|
||||
}
|
||||
};
|
||||
#else
|
||||
# include "nsCRT.h"
|
||||
#endif
|
||||
|
||||
#include "nsStringMap.h"
|
||||
|
||||
const char nsStringMap::zero_str[] = "\0";
|
||||
|
||||
nsStringMap::~nsStringMap()
|
||||
{
|
||||
// Get rid of the arena memory
|
||||
PL_FinishArenaPool(&mPool);
|
||||
}
|
||||
|
||||
nsStringMap::nsStringMap() : numEntries(0)
|
||||
{
|
||||
// Initialize the head
|
||||
head.l = head.r = &head;
|
||||
head.bit = ~0;
|
||||
head.key = zero_str;
|
||||
head.len = 1;
|
||||
head.obj = 0;
|
||||
|
||||
// Initialize the arena. Guess that a 512 byte block size is good
|
||||
PL_InitArenaPool(&mPool, "nsStringMap", 512, sizeof(void*));
|
||||
}
|
||||
|
||||
void
|
||||
nsStringMap::Reset()
|
||||
{
|
||||
// Initialize the head
|
||||
head.l = head.r = &head;
|
||||
head.bit = ~0;
|
||||
head.key = zero_str;
|
||||
head.len = 1;
|
||||
head.obj = 0;
|
||||
|
||||
// Reinitialize the Arena
|
||||
PL_FinishArenaPool(&mPool);
|
||||
PL_InitArenaPool(&mPool, "nsStringMap", 512, sizeof(void*));
|
||||
}
|
||||
|
||||
void
|
||||
nsStringMap::Reset(nsStringMapEnumFunc destroyFunc, void *aClosure)
|
||||
{
|
||||
Enumerate(destroyFunc, aClosure);
|
||||
Reset();
|
||||
}
|
||||
|
||||
nsStringMap::Patricia *
|
||||
nsStringMap::newNode()
|
||||
{
|
||||
return (Patricia*) PL_ArenaAllocate(&mPool, sizeof(Patricia));
|
||||
}
|
||||
|
||||
nsStringMap::Patricia *
|
||||
nsStringMap::searchDown(BitTester &key)
|
||||
{
|
||||
// The head node only branches to the left, so we can optimize here.
|
||||
Patricia *x = head.l;
|
||||
|
||||
PRUint32 lastBits;
|
||||
|
||||
do {
|
||||
lastBits = x->bit;
|
||||
|
||||
if(key.isset(lastBits))
|
||||
x = x->r;
|
||||
else
|
||||
x = x->l;
|
||||
|
||||
} while(lastBits > x->bit);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void*
|
||||
nsStringMap::Get(const char *str, PRUint32 slen)
|
||||
{
|
||||
BitTester key(str, slen);
|
||||
|
||||
Patricia *t = searchDown(key);
|
||||
|
||||
if(!key.memcmp(t->key, t->len)) {
|
||||
return t->obj;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
nsStringMap::Get(const char *str)
|
||||
{
|
||||
BitTester key(str);
|
||||
|
||||
Patricia *t = searchDown(key);
|
||||
|
||||
if(!key.memcmp(t->key, t->len)) {
|
||||
return t->obj;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsStringMap::Put(const char *str, void *obj, PRBool copy)
|
||||
{
|
||||
PRUint32 slen = nsCRT::strlen(str);
|
||||
return Put(str, slen, obj, copy);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsStringMap::Put(const char *str, PRUint32 slen, void *obj, PRBool copy)
|
||||
{
|
||||
if(copy) {
|
||||
PRUint32 mask = sizeof(double) - 1;
|
||||
PRUint32 asize = (slen+mask) & ~mask;
|
||||
char *tstr = (char*) PL_ArenaAllocate(&mPool, asize);
|
||||
memcpy(tstr, str, slen);
|
||||
str = tstr;
|
||||
}
|
||||
|
||||
BitTester key(str, slen);
|
||||
|
||||
Patricia *t = searchDown(key);
|
||||
|
||||
if(!key.memcmp(t->key, t->len)) {
|
||||
t->obj = obj;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// This is somewhat ugly. We need to find the maximum bit position that
|
||||
// differs, but this is complicated by the fact that we have random length
|
||||
// data. Assume that data past the end of the string is 0.
|
||||
const PRUint32 klen = key.datalen();
|
||||
const PRUint32 tlen = t->len;
|
||||
PRUint32 bpos;
|
||||
if(klen>tlen) {
|
||||
bpos = 8 * klen - 1;
|
||||
while(!BitTester::isset_checked(str, bpos)) --bpos;
|
||||
} else if(tlen>klen) {
|
||||
bpos = 8 * tlen - 1;
|
||||
while(!BitTester::isset_checked(t->key, bpos)) --bpos;
|
||||
} else /* equal */ {
|
||||
bpos = 8 * tlen - 1;
|
||||
while(BitTester::bitsequal(t->key, str, bpos)) --bpos;
|
||||
}
|
||||
|
||||
Patricia *p, *x = &head;
|
||||
|
||||
do {
|
||||
p = x;
|
||||
x = key.isset(x->bit) ? x->r : x->l;
|
||||
} while(x->bit > bpos && p->bit > x->bit);
|
||||
|
||||
t = newNode();
|
||||
|
||||
if(!t) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
t->key = str;
|
||||
t->len = key.datalen();
|
||||
t->obj = obj;
|
||||
t->bit = bpos;
|
||||
|
||||
if(key.isset(t->bit)) {
|
||||
t->r = t;
|
||||
t->l = x;
|
||||
} else {
|
||||
t->r = x;
|
||||
t->l = t;
|
||||
}
|
||||
|
||||
if(key.isset(p->bit)) {
|
||||
p->r = t;
|
||||
} else {
|
||||
p->l = t;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsStringMap::enumerate_recurse(
|
||||
nsStringMapEnumFunc aEnumFunc, void* aClosure, Patricia *node)
|
||||
{
|
||||
aEnumFunc(node->key, node->obj, aClosure);
|
||||
if(node->l && node->l->bit<node->bit)
|
||||
enumerate_recurse(aEnumFunc, aClosure, node->l);
|
||||
if(node->r && node->r->bit<node->bit)
|
||||
enumerate_recurse(aEnumFunc, aClosure, node->r);
|
||||
}
|
||||
|
||||
void
|
||||
nsStringMap::Enumerate(nsStringMapEnumFunc aEnumFunc, void *aClosure)
|
||||
{
|
||||
// We dont want to process head, its a sentinal
|
||||
if(head.l && head.l->bit<head.bit)
|
||||
enumerate_recurse(aEnumFunc, aClosure, head.l);
|
||||
if(head.r && head.r->bit<head.bit)
|
||||
enumerate_recurse(aEnumFunc, aClosure, head.r);
|
||||
}
|
||||
|
||||
#if defined(TEST_PATRICIA)
|
||||
|
||||
PRBool etest(const char *key, void *data, void *closure)
|
||||
{
|
||||
printf("%s\n", key);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
nsStringMap map;
|
||||
const char *strings[] = {
|
||||
"I am number 1 string",
|
||||
"I am number 2 string",
|
||||
"I am number 3 string",
|
||||
"a different string",
|
||||
"a similar string",
|
||||
"I am a very long string and I want to make sure we can handle this",
|
||||
"I am a very long string and I want to make sure we can handle this too",
|
||||
0
|
||||
};
|
||||
|
||||
int idx;
|
||||
for(idx=0; strings[idx]; ++idx) {
|
||||
map.Put(strings[idx], (void*)(1+idx));
|
||||
}
|
||||
|
||||
printf("Lookup Test\n");
|
||||
while(--idx>=0) {
|
||||
void *ptr = map.Get(strings[idx]);
|
||||
printf("%d: %s\n", (long)ptr, strings[idx]);
|
||||
}
|
||||
|
||||
printf("\nEnumeration Test\n");
|
||||
|
||||
map.Enumerate(etest, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
#ifndef nsStringMap_h__
|
||||
#define nsStringMap_h__
|
||||
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is James L. Nance
|
||||
* Portions created by James L. Nance are Copyright (C) 2001
|
||||
* James L. Nance. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Patricia Jewell Nance, Jesse Jacob Nance
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#if !defined(TEST_PATRICIA)
|
||||
# include "nscore.h"
|
||||
# include "prtypes.h"
|
||||
# include "plarena.h"
|
||||
#endif
|
||||
|
||||
typedef PRBool (*PR_CALLBACK nsStringMapEnumFunc) (
|
||||
const char *aKey, void *aData, void *aClosure);
|
||||
|
||||
class nsStringMap
|
||||
{
|
||||
public:
|
||||
nsStringMap();
|
||||
~nsStringMap();
|
||||
PRBool Put(const char *str, PRUint32 slen, void *obj, PRBool copy=PR_FALSE);
|
||||
PRBool Put(const char *str, void *obj, PRBool copy=PR_FALSE);
|
||||
void* Get(const char *str);
|
||||
void* Get(const char *str, PRUint32 slen);
|
||||
void Reset();
|
||||
void Reset(nsStringMapEnumFunc destroyFunc, void *aClosure = 0);
|
||||
void Enumerate(nsStringMapEnumFunc aEnumFunc, void *aClosure = 0);
|
||||
|
||||
struct Patricia {
|
||||
Patricia *l, *r;
|
||||
PRUint32 bit; // Bit position for l/r comp
|
||||
const char *key;
|
||||
PRUint32 len;
|
||||
void *obj;
|
||||
};
|
||||
|
||||
// The BitTester class is used to test a particular bit position in an
|
||||
// array of characters. It does not assign any special meaning to 0
|
||||
// characters. Bits past the end of the array are treated as 0
|
||||
class BitTester {
|
||||
const PRUint32 slen;
|
||||
const char *cstr;
|
||||
public:
|
||||
BitTester(const char *s) : slen(nsCRT::strlen(s)), cstr(s) {}
|
||||
BitTester(const char *s, PRUint32 l) : slen(l), cstr(s) {}
|
||||
|
||||
PRInt32 memcmp(const char *ostr, PRUint32 olen) {
|
||||
if(olen==slen) {
|
||||
return ::memcmp((void*)cstr, ostr, slen);
|
||||
} else {
|
||||
return olen - slen;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 datalen() const {return slen;}
|
||||
|
||||
static PRBool isset_checked(const char *str, PRUint32 idx) {
|
||||
return (str[idx/8] & (1<<(idx & 7))) != 0;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
bitsequal(const char *str1, const char*str2, PRUint32 idx) {
|
||||
return (str1[idx/8] & (1<<(idx&7)))==(str2[idx/8] & (1<<(idx&7)));
|
||||
}
|
||||
|
||||
PRBool isset(PRUint32 idx) {
|
||||
const PRUint32 base = idx/8;
|
||||
if(base>=slen) return 0;
|
||||
return (cstr[base] & (1<<(idx & 7))) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
PLArenaPool mPool;
|
||||
Patricia *newNode();
|
||||
Patricia *searchDown(BitTester&);
|
||||
void enumerate_recurse(nsStringMapEnumFunc, void*, Patricia*);
|
||||
Patricia head; // Sentinal node
|
||||
PRInt32 numEntries;
|
||||
static const char zero_str[];
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user