Merge from mozilla-inbound to mozilla-central

This commit is contained in:
Matt Brubeck 2011-12-27 11:04:58 -08:00
Родитель 20ec9c27ca 81a557d6a3
Коммит b40bc2a90b
90 изменённых файлов: 3437 добавлений и 448 удалений

Просмотреть файл

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
/**
* TestCase for bug 564387
@ -54,7 +54,7 @@ function test() {
registerCleanupFunction(function () {
mockTransferRegisterer.unregister();
MockFilePicker.reset();
MockFilePicker.cleanup();
destDir.remove(true);
});

Просмотреть файл

@ -14,7 +14,6 @@
; Mac bundle stuff
@APPNAME@/Contents/Info.plist
@APPNAME@/Contents/PkgInfo
@APPNAME@/Contents/Plug-Ins/
@APPNAME@/Contents/Resources/
#endif

Просмотреть файл

@ -373,6 +373,13 @@ ifdef MAPFILE
OS_LDFLAGS += -MAP:$(MAPFILE)
endif
else #!GNU_CC
ifdef DEFFILE
OS_LDFLAGS += $(call normalizepath,$(DEFFILE))
EXTRA_DEPS += $(DEFFILE)
endif
endif # !GNU_CC
endif # WINNT

Просмотреть файл

@ -18,7 +18,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=500885
<script type="text/javascript">
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
MockFilePicker.returnValue = MockFilePicker.returnOK;
function test() {
@ -47,7 +47,10 @@ function test() {
is(domActivateEvents, 1, "click on button should fire 1 DOMActivate event");
} finally {
SimpleTest.executeSoon(SimpleTest.finish);
SimpleTest.executeSoon(function() {
MockFilePicker.cleanup();
SimpleTest.finish();
});
}
}

Просмотреть файл

@ -26,7 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=592802
SimpleTest.waitForExplicitFinish();
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
var testData = [
/* visibility | display | multiple */
@ -43,6 +43,7 @@ var testNb = testData.length;
function finished()
{
MockFilePicker.cleanup();
SimpleTest.finish();
}

Просмотреть файл

@ -1112,6 +1112,24 @@ nsSVGElement::UpdateContentStyleRule()
if (!attrName->IsAtom() || !IsAttributeMapped(attrName->Atom()))
continue;
if (Tag() == nsGkAtoms::svg) {
// Special case: we don't want <svg> 'width'/'height' mapped into style
// if the attribute value isn't a valid <length> according to SVG (which
// only supports a subset of the CSS <length> values). We don't enforce
// this by checking the attribute value in nsSVGSVGElement::
// IsAttributeMapped since we don't want that method to depend on the
// value of the attribute that is being checked. Rather we just prevent
// the actual mapping here, as necessary.
if (attrName->Atom() == nsGkAtoms::width &&
!GetAnimatedLength(nsGkAtoms::width)->HasBaseVal()) {
continue;
}
if (attrName->Atom() == nsGkAtoms::height &&
!GetAnimatedLength(nsGkAtoms::height)->HasBaseVal()) {
continue;
}
}
nsAutoString value;
mAttrsAndChildren.AttrAt(i)->ToString(value);
mappedAttrParser.ParseMappedAttrValue(attrName->Atom(), value);
@ -1314,6 +1332,20 @@ nsSVGElement::DidAnimateLength(PRUint8 aAttrEnum)
}
}
nsSVGLength2*
nsSVGElement::GetAnimatedLength(const nsIAtom *aAttrName)
{
LengthAttributesInfo lengthInfo = GetLengthInfo();
for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
if (aAttrName == *lengthInfo.mLengthInfo[i].mName) {
return &lengthInfo.mLengths[i];
}
}
NS_ABORT_IF_FALSE(false, "no matching length found");
return nsnull;
}
void
nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...)
{

Просмотреть файл

@ -195,6 +195,7 @@ public:
virtual void DidAnimateTransformList();
virtual void DidAnimateString(PRUint8 aAttrEnum);
nsSVGLength2* GetAnimatedLength(const nsIAtom *aAttrName);
void GetAnimatedLengthValues(float *aFirst, ...);
void GetAnimatedNumberValues(float *aFirst, ...);
void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);

Просмотреть файл

@ -100,6 +100,9 @@ public:
float GetAnimValue(nsSVGSVGElement* aCtx) const
{ return mAnimVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
bool HasBaseVal() const {
return mIsBaseSet;
}
// Returns true if the animated value of this length has been explicitly
// set (either by animation, or by taking on the base value which has been
// explicitly set by markup or a DOM call), false otherwise.

Просмотреть файл

@ -883,6 +883,20 @@ nsSVGSVGElement::GetTimedDocumentRoot()
NS_IMETHODIMP_(bool)
nsSVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
{
// We want to map the 'width' and 'height' attributes into style for
// outer-<svg>, except when the attributes aren't set (since their default
// values of '100%' can cause unexpected and undesirable behaviour for SVG
// inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
// prevent mapping of the default values into style (it only maps attributes
// that are set). We also rely on a check in nsSVGElement::
// UpdateContentStyleRule() to prevent us mapping the attributes when they're
// given a <length> value that is not currently recognized by the SVG
// specification.
if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
return true;
}
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,

Просмотреть файл

@ -79,6 +79,9 @@
#include "Worker.h"
#include "WorkerFeature.h"
#include "WorkerScope.h"
#ifdef ANDROID
#include <android/log.h>
#endif
#include "WorkerInlines.h"
@ -1149,7 +1152,11 @@ public:
}
if (!logged) {
fputs(NS_ConvertUTF16toUTF8(aMessage).get(), stderr);
NS_ConvertUTF16toUTF8 msg(aMessage);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", msg.get());
#endif
fputs(msg.get(), stderr);
fflush(stderr);
}

Просмотреть файл

@ -61,6 +61,9 @@
#include "Worker.h"
#include "WorkerPrivate.h"
#include "XMLHttpRequest.h"
#ifdef ANDROID
#include <android/log.h>
#endif
#include "WorkerInlines.h"
@ -517,6 +520,9 @@ private:
return false;
}
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", buffer.ptr());
#endif
fputs(buffer.ptr(), stderr);
fflush(stderr);
}

Просмотреть файл

@ -302,22 +302,15 @@ EXPORTS_skia += \
$(NULL)
CPPSRCS += \
SkFontHost_mac_coretext.cpp \
SkBitmapProcState_opts_SSE2.cpp \
SkBlitRow_opts_SSE2.cpp \
SkUtils_opts_SSE2.cpp \
opts_check_SSE2.cpp \
SkTime_Unix.cpp \
$(NULL)
endif
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
SkBitmapProcState_opts_arm.cpp \
SkBlitRow_opts_arm.cpp \
SkFontHost_FreeType.cpp \
SkFontHost_android.cpp \
SkFontHost_gamma.cpp \
SkUtils_opts_none.cpp \
SkMMapStream.cpp \
SkTime_Unix.cpp \
$(NULL)
@ -334,11 +327,31 @@ EXPORTS_skia += \
CPPSRCS += \
SkFontHost_win.cpp \
SkTime_win.cpp \
$(NULL)
endif
ifneq (,$(INTEL_ARCHITECTURE))
CPPSRCS += \
SkBitmapProcState_opts_SSE2.cpp \
SkBlitRow_opts_SSE2.cpp \
SkUtils_opts_SSE2.cpp \
opts_check_SSE2.cpp \
$(NULL)
else
ifeq ($(CPU_ARCH)_$(GNU_CC),arm_1)
CPPSRCS += \
SkBitmapProcState_opts_arm.cpp \
SkBlitRow_opts_arm.cpp \
opts_check_arm.cpp \
$(NULL)
SSRCS += memset.arm.S
else
CPPSRCS += \
SkBitmapProcState_opts_none.cpp \
SkBlitRow_opts_none.cpp \
SkUtils_opts_none.cpp \
$(NULL)
endif
endif
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -373,6 +373,13 @@ ifdef MAPFILE
OS_LDFLAGS += -MAP:$(MAPFILE)
endif
else #!GNU_CC
ifdef DEFFILE
OS_LDFLAGS += $(call normalizepath,$(DEFFILE))
EXTRA_DEPS += $(DEFFILE)
endif
endif # !GNU_CC
endif # WINNT

Просмотреть файл

@ -24,7 +24,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=36619
SimpleTest.waitForExplicitFinish();
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
// enable popups the first time
SpecialPowers.pushPrefEnv({'set': [
@ -45,7 +45,7 @@ SpecialPowers.pushPrefEnv({'set': [
document.getElementById("a").click();
SimpleTest.executeSoon(function() {
ok(!MockFilePicker.shown, "File picker show method should not have been called");
MockFilePicker.reset();
MockFilePicker.cleanup();
SimpleTest.finish();
});

Просмотреть файл

@ -33,7 +33,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=377624
SimpleTest.waitForExplicitFinish();
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
var testData = [["a", MockFilePicker.filterImages, 1],
["b", MockFilePicker.filterAudio, 1],
@ -88,7 +88,7 @@ function runTests() {
"File picker should show the correct filter index");
if (++currentTest == testData.length) {
MockFilePicker.reset();
MockFilePicker.cleanup();
SimpleTest.finish();
} else {
launchNextTest();

Просмотреть файл

@ -24,7 +24,7 @@ const Cu = Components.utils;
const Cm = Components.manager;
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
var ioSvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
@ -134,7 +134,7 @@ function endTest() {
dirs[i].remove(true);
}
MockFilePicker.reset();
MockFilePicker.cleanup();
SimpleTest.finish();
}

Просмотреть файл

@ -20,6 +20,7 @@ nestegg_track_type
nestegg_track_video_params
nestegg_tstamp_scale
#ifndef MOZ_NATIVE_LIBVPX
vpx_codec_control_
vpx_codec_dec_init_ver
vpx_codec_decode
vpx_codec_destroy

Просмотреть файл

@ -0,0 +1,38 @@
<html class="reftest-print">
<head>
<title>push rowspan on to next page if it can't be splitted</title>
<style>
img {
width: 10px;
height: 30px;
}
</style>
</head>
<body>
<div style="height: 110px"></div>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td></td>
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
<tr style="page-break-after:always">
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
<tr>
<td rowspan="2">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
<td rowspan="2"></td>
</tr>
<tr>
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,38 @@
<html class="reftest-print">
<head>
<title>push rowspan on to next page if it can't be splitted</title>
<style>
img {
width: 10px;
height: 30px;
}
</style>
</head>
<body>
<div style="height: 110px"></div>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td></td>
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
<tr>
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
<tr>
<td rowspan="2">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
<td rowspan="2"></td>
</tr>
<tr>
<td>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF/wAAAAAAQaMSAwAAABJJREFUeNpiYBgFo2AwAIAAAwACigABtnCV2AAAAABJRU5ErkJggg==">
</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<body>
<table style="border-collapse: collapse;" border="1">
<tbody id="reference">
<tr><td>&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
</tbody>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script>
var lastLang = "";
function LangSelect(aLang) {
var tbody = document.getElementById("l10ntbody");
var child = tbody.firstChild;
while (child) {
if (child.nodeType == Node.ELEMENT_NODE) {
if (aLang == "*" || aLang == child.getAttribute("language"))
child.removeAttribute("style");
else
child.setAttribute("style", "display: none");
}
child = child.nextSibling;
}
}
</script>
</head>
<body onload="LangSelect('cs');">
<table style="border-collapse: collapse;" border="1">
<tbody id="l10ntbody">
<tr style="display: none;" language="cs"><td>&nbsp;</td></tr>
<tr style="display: none;" language="cs"><td>&nbsp;</td></tr>
<tr style="display: none;" language="cs"><td>&nbsp;</td></tr>
</tbody>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>testcase</title>
<style>
.tt {
border-collapse: collapse;
}
.nix {
display: none;
}
.ref {
border: solid 3px darkred;
}
td {
width: 20px;
height: 20px;
}
</style>
</head>
<body>
<table class="tt">
<tr id="1"><td >&nbsp;</td></tr>
<tr id="2" class="nix"><td >&nbsp;</td></tr>
<tr id="3" class="ref"><td >&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>testcase</title>
<style>
.tt {
border-collapse: collapse;
}
.nix {
display: none;
}
.ref {
border: solid 3px darkred;
}
td {
width: 20px;
height: 20px;
}
</style>
<script>
function test ()
{
document.getElementById ("2").className = "nix";
document.getElementById ("3").className = "ref";
}
</script>
</head>
<body onload="test()">
<table class="tt">
<tr id="1"><td >&nbsp;</td></tr>
<tr id="2"><td >&nbsp;</td></tr>
<tr id="3"><td >&nbsp;</td></tr>
<tr><td>&nbsp;</td></tr>
</table>
</body>
</html>

Просмотреть файл

@ -1445,6 +1445,7 @@ random-if(d2d) == 523468-1.html 523468-1-ref.html
== 528096-1.html 528096-1-ref.html
== 530686-1.html 530686-1-ref.html
== 531098-1.html 531098-1-ref.html
== 531200-1.html 531200-1-ref.html
== 531371-1.html 531371-1-ref.html
== 534526-1a.html 534526-1-ref.html
== 534526-1b.html 534526-1-ref.html
@ -1677,3 +1678,5 @@ fails-if(layersGPUAccelerated&&cocoaWidget) == 654950-1.html 654950-1-ref.html #
needs-focus == 703186-1.html 703186-1-ref.html
needs-focus == 703186-2.html 703186-2-ref.html
needs-focus != 703186-1.html 703186-2.html
== 711359-1.html 711359-1-ref.html
== 712849-1.html 712849-1-ref.html

Просмотреть файл

@ -1,52 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=294086 -->
<title>Test: resize of container block height</title>
<!--
This testcase checks that SVG embedded inline with a percentage height is
updated correctly when its containing block is resized.
-->
<style type="text/css">
html, body, div {
padding: 0;
border: 0;
margin: 0;
width: 100%;
height: 100%; /* inline style override on the div below */
background: white;
overflow: hidden;
}
</style>
<script type="text/javascript">
function resize_div()
{
var XHTML_NS = 'http://www.w3.org/1999/xhtml';
document.getElementsByTagNameNS(XHTML_NS, 'div').item(0).style.height = '100%';
document.documentElement.removeAttribute('class');
}
document.addEventListener("MozReftestInvalidate", resize_div, false);
</script>
</head>
<body>
<div style="height:50%;">
<svg xmlns="http://www.w3.org/2000/svg" width="5000" height="100%">
<rect width="100%" height="100%" fill="blue"/>
</svg>
</div>
</body>
</html>

Просмотреть файл

@ -1,52 +0,0 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
<head>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=294086 -->
<title>Test: resize of container block width</title>
<!--
This testcase checks that SVG embedded inline with a percentage width is
updated correctly when its containing block is resized.
-->
<style type="text/css">
html, body, div {
padding: 0;
border: 0;
margin: 0;
width: 100%; /* inline style override on the div below */
height: 100%;
background: white;
overflow: hidden;
}
</style>
<script type="text/javascript">
function resize_div()
{
var XHTML_NS = 'http://www.w3.org/1999/xhtml';
document.getElementsByTagNameNS(XHTML_NS, 'div').item(0).style.width = '100%';
document.documentElement.removeAttribute('class');
}
document.addEventListener("MozReftestInvalidate", resize_div, false);
</script>
</head>
<body>
<div style="width:50%;">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="5000">
<rect width="100%" height="100%" fill="blue"/>
</svg>
</div>
</body>
</html>

Просмотреть файл

@ -303,10 +303,6 @@ random-if(Android) == object--auto-auto--px-px.html object--auto-auto--px
== dynamic--inline-css-height.xhtml pass.svg
== dynamic--inline-css-width.xhtml pass.svg
# These two don't have a whole lot of point anymore now that the meaning
# of percentages has changed.
== dynamic--inline-resize-cb-height.xhtml standalone-sanity-height-150px.svg
== dynamic--inline-resize-cb-width.xhtml standalone-sanity-width-300px.svg
skip == dynamic--inline-resize-window-height.xhtml pass.svg # XXX breaks the reftest run as the window height somehow is not restored
skip == dynamic--inline-resize-window-width.xhtml pass.svg # Fails way too much
fails random-if(Android) == dynamic--object-svg-unloaded.xhtml pass.svg

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Blake Ross <BlakeR1234@aol.com>
* Geoff Lankow <geoff@darktrojan.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -47,6 +48,7 @@
font-family: -moz-fixed;
font-weight: normal;
white-space: pre;
counter-reset: line;
}
#viewsource.wrap {
white-space: pre-wrap;
@ -56,7 +58,20 @@ pre {
font: inherit;
color: inherit;
white-space: inherit;
margin: 0;
margin: 0 0 0 5ch;
}
pre[id]:before,
span[id]:before {
content: counter(line) " ";
counter-increment: line;
-moz-user-select: none;
display: inline-block;
width: 5ch;
margin: 0 0 0 -5ch;
text-align: right;
color: #ccc;
font-weight: normal;
font-style: normal;
}
.start-tag {
color: purple;

Просмотреть файл

@ -59,7 +59,7 @@ load 385552-2.svg
load 385840-1.svg
load 385852-1.svg
load 386475-1.xhtml
load 386566-1.svg
asserts(1) load 386566-1.svg # Bug 713626
load 386690-1.svg
load 387290-1.svg
load 402408-1.svg

Просмотреть файл

@ -1860,8 +1860,11 @@ nsCellMap::ExpandWithRows(nsTableCellMap& aMap,
}
newRowIndex++;
}
SetDamageArea(0, aRgFirstRowIndex + startRowIndex, aMap.GetColCount(),
1 + endRowIndex - startRowIndex, aDamageArea);
// mark all following rows damaged, they might contain a previously set
// damage area which we can not shift.
PRInt32 firstDamagedRow = aRgFirstRowIndex + startRowIndex;
SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
aMap.GetRowCount() - firstDamagedRow, aDamageArea);
}
void nsCellMap::ExpandWithCells(nsTableCellMap& aMap,
@ -2028,8 +2031,11 @@ void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap,
mContentRowCount--;
}
aMap.RemoveColsAtEnd();
SetDamageArea(0, aRgFirstRowIndex + aStartRowIndex, aMap.GetColCount(), 0,
aDamageArea);
// mark all following rows damaged, they might contain a previously set
// damage area which we can not shift.
PRInt32 firstDamagedRow = aRgFirstRowIndex + aStartRowIndex;
SetDamageArea(0, firstDamagedRow, aMap.GetColCount(),
aMap.GetRowCount() - firstDamagedRow, aDamageArea);
}
PRInt32 nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd,

Просмотреть файл

@ -206,20 +206,14 @@ nsTableRowFrame::AppendFrames(ChildListID aListID,
{
NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
// Append the frames
// XXXbz why do we append here first, then append to table, while
// for InsertFrames we do it in the other order? Bug 507419 covers this.
const nsFrameList::Slice& newCells = mFrames.AppendFrames(nsnull, aFrameList);
// Add the new cell frames to the table
nsTableFrame *tableFrame = nsTableFrame::GetTableFrame(this);
for (nsFrameList::Enumerator e(newCells) ; !e.AtEnd(); e.Next()) {
nsTableCellFrame *cellFrame = do_QueryFrame(e.get());
NS_ASSERTION(cellFrame, "Unexpected frame");
if (cellFrame) {
// Add the cell to the cell map
tableFrame->AppendCell(*cellFrame, GetRowIndex());
}
nsIFrame *childFrame = e.get();
NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
tableFrame->AppendCell(static_cast<nsTableCellFrame&>(*childFrame), GetRowIndex());
}
PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
@ -238,22 +232,19 @@ nsTableRowFrame::InsertFrames(ChildListID aListID,
NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
"inserting after sibling frame with different parent");
//Insert Frames in the frame list
const nsFrameList::Slice& newCells = mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
// Get the table frame
nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
// gather the new frames (only those which are cells) into an array
// XXXbz there shouldn't be any other ones here... can we just put
// them all in the array and not do all this QI nonsense?
nsIAtom* cellFrameType = (tableFrame->IsBorderCollapse()) ? nsGkAtoms::bcTableCellFrame : nsGkAtoms::tableCellFrame;
nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, cellFrameType);
nsTArray<nsTableCellFrame*> cellChildren;
for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
nsTableCellFrame *cellFrame = do_QueryFrame(e.get());
NS_ASSERTION(cellFrame, "Unexpected frame");
if (cellFrame) {
cellChildren.AppendElement(cellFrame);
}
for (nsFrameList::Enumerator e(newCells); !e.AtEnd(); e.Next()) {
nsIFrame *childFrame = e.get();
NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
cellChildren.AppendElement(static_cast<nsTableCellFrame*>(childFrame));
}
// insert the cells into the cell map
PRInt32 colIndex = -1;
@ -261,9 +252,6 @@ nsTableRowFrame::InsertFrames(ChildListID aListID,
prevCellFrame->GetColIndex(colIndex);
}
tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex);
// Insert the frames in the frame list
mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
NS_FRAME_HAS_DIRTY_CHILDREN);

Просмотреть файл

@ -955,6 +955,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext,
static_cast<nsTableFrame*>(aTable.GetFirstInFlow())->IsBorderCollapse();
PRInt32 lastRowIndex = aLastRow.GetRowIndex();
bool wasLast = false;
bool haveRowSpan = false;
// Iterate the rows between aFirstRow and aLastRow
for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
wasLast = (row == &aLastRow);
@ -966,6 +967,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext,
// Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
// were reflowed correctly during the unconstrained height reflow.
if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
haveRowSpan = true;
nsReflowStatus status;
// Ask the row to reflow the cell to the height of all the rows it spans up through aLastRow
// aAvailHeight is the space between the row group start and the end of the page
@ -1021,6 +1023,9 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext,
}
}
}
if (!haveRowSpan) {
aDesiredHeight = aLastRow.GetRect().YMost();
}
}
// Remove the next-in-flow of the row, its cells and their cell blocks. This

Просмотреть файл

@ -1,4 +1,4 @@
; ***** BEGIN LICENSE BLOCK *****
; ***** BEGIN LICENSE BLOCK *****
; Version: MPL 1.1/GPL 2.0/LGPL 2.1
;
; The contents of this file are subject to the Mozilla Public License Version

Просмотреть файл

@ -68,10 +68,13 @@ import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.ListView;
import java.util.Map;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.db.BrowserDB;
@ -386,48 +389,75 @@ public class AwesomeBar extends Activity implements GeckoEventListener {
GeckoAppShell.unregisterGeckoEventListener("SearchEngines:Data", this);
}
private Cursor mContextMenuCursor = null;
private Object mContextMenuSubject = null;
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
ListView list = (ListView) view;
Object selecteditem = list.getItemAtPosition(info.position);
Object selectedItem = null;
String title = "";
if (!(selecteditem instanceof Cursor)) {
mContextMenuCursor = null;
if (view == (ListView)findViewById(R.id.history_list)) {
ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
ExpandableListView exList = (ExpandableListView)list;
int childPosition = exList.getPackedPositionChild(info.packedPosition);
int groupPosition = exList.getPackedPositionGroup(info.packedPosition);
selectedItem = exList.getExpandableListAdapter().getChild(groupPosition, childPosition);
Map<String, Object> map = (Map<String, Object>)selectedItem;
title = (String)map.get(URLColumns.TITLE);
} else {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
selectedItem = list.getItemAtPosition(info.position);
Cursor cursor = (Cursor)selectedItem;
title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
}
if (selectedItem == null || !((selectedItem instanceof Cursor) || (selectedItem instanceof Map))) {
mContextMenuSubject = null;
return;
}
mContextMenuCursor = (Cursor) selecteditem;
mContextMenuSubject = selectedItem;
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.awesomebar_contextmenu, menu);
String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
menu.setHeaderTitle(title);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (mContextMenuCursor == null)
if (mContextMenuSubject == null)
return false;
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
String url = "";
byte[] b = null;
String title = "";
if (mContextMenuSubject instanceof Cursor) {
Cursor cursor = (Cursor)mContextMenuSubject;
url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
b = (byte[]) cursor.getBlob(cursor.getColumnIndexOrThrow(URLColumns.FAVICON));
title = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.TITLE));
} else if (mContextMenuSubject instanceof Map) {
Map<String, Object> map = (Map<String, Object>)mContextMenuSubject;
url = (String)map.get(URLColumns.URL);
b = (byte[]) map.get(URLColumns.FAVICON);
title = (String)map.get(URLColumns.TITLE);
} else {
return false;
}
mContextMenuSubject = null;
switch (item.getItemId()) {
case R.id.open_new_tab: {
String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
GeckoApp.mAppContext.loadUrl(url, AwesomeBar.Type.ADD);
break;
}
case R.id.add_to_launcher: {
String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
byte[] b = (byte[]) mContextMenuCursor.getBlob(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.FAVICON));
String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
Bitmap bitmap = null;
if (b != null)
bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
@ -436,18 +466,14 @@ public class AwesomeBar extends Activity implements GeckoEventListener {
break;
}
case R.id.share: {
String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, title);
break;
}
default: {
mContextMenuCursor = null;
return super.onContextItemSelected(item);
}
}
mContextMenuCursor = null;
return true;
}

Просмотреть файл

@ -142,7 +142,7 @@ public class GeckoPreferences
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String prefName = preference.getKey();
if (prefName.equals("privacy.masterpassword.enabled")) {
if (prefName != null && prefName.equals("privacy.masterpassword.enabled")) {
showDialog((Boolean)newValue ? DIALOG_CREATE_MASTER_PASSWORD : DIALOG_REMOVE_MASTER_PASSWORD);
return false;
}

Просмотреть файл

@ -141,7 +141,7 @@ public class Tabs implements GeckoEventListener {
/** Close tab and then select nextTab */
public void closeTab(Tab tab, Tab nextTab) {
if (tab == null)
if (tab == null || nextTab == null)
return;
GeckoAppShell.sendEventToGecko(new GeckoEvent("Tab:Select", String.valueOf(nextTab.getId())));

Просмотреть файл

@ -959,6 +959,7 @@ public class PanZoomController
mState = PanZoomState.PINCHING;
mLastZoomFocus = new PointF(detector.getFocusX(), detector.getFocusY());
GeckoApp.mAppContext.hidePluginViews();
GeckoApp.mAppContext.mAutoCompletePopup.hide();
cancelTouch();
return true;
@ -1075,6 +1076,7 @@ public class PanZoomController
private boolean animatedZoomTo(RectF zoomToRect) {
GeckoApp.mAppContext.hidePluginViews();
GeckoApp.mAppContext.mAutoCompletePopup.hide();
mState = PanZoomState.ANIMATED_ZOOM;
final float startZoom = mController.getZoomFactor();

Просмотреть файл

@ -84,11 +84,12 @@
<li><a href="about:rights">&aboutPage.rights.label;</a></li>
<li><a id="releaseNotesURL">&aboutPage.relNotes.label;</a></li>
<li><a id="creditsURL">&aboutPage.credits.label;</a></li>
<li><a href="about:license">&aboutPage.license.label;</a></li>
<div class="bottom-border"></div>
</ul>
<div id="aboutDetails">
<p id="license"><b><a href="about:license">&aboutPage.licenseLink;</a>&aboutPage.licenseLinkSuffix;</b> &logoTrademark;</p>
<p>&logoTrademark;</p>
</div>
<script type="application/javascript;version=1.8"><![CDATA[

Просмотреть файл

@ -3341,7 +3341,7 @@ var PluginHelper = {
var PermissionsHelper = {
_permissonTypes: ["password", "geo", "popup", "indexedDB",
_permissonTypes: ["password", "geolocation", "popup", "indexedDB",
"offline-app", "desktop-notification"],
_permissionStrings: {
"password": {
@ -3349,10 +3349,10 @@ var PermissionsHelper = {
allowed: "password.remember",
denied: "password.never"
},
"geo": {
"geolocation": {
label: "geolocation.shareLocation",
allowed: "geolocation.alwaysShare",
denied: "geolocation.neverShare"
allowed: "geolocation.alwaysAllow",
denied: "geolocation.neverAllow"
},
"popup": {
label: "blockPopups.label",
@ -3444,7 +3444,7 @@ var PermissionsHelper = {
*
* @param aType
* The permission type string stored in permission manager.
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
* e.g. "geolocation", "indexedDB", "popup"
*
* @return A permission value defined in nsIPermissionManager.
*/
@ -3465,7 +3465,7 @@ var PermissionsHelper = {
}
// Geolocation consumers use testExactPermission
if (aType == "geo")
if (aType == "geolocation")
return Services.perms.testExactPermission(aURI, aType);
return Services.perms.testPermission(aURI, aType);
@ -3476,7 +3476,7 @@ var PermissionsHelper = {
*
* @param aType
* The permission type string stored in permission manager.
* e.g. "cookie", "geo", "indexedDB", "popup", "image"
* e.g. "geolocation", "indexedDB", "popup"
*/
clearPermission: function clearPermission(aURI, aType) {
// Password saving isn't a nsIPermissionManager permission type, so handle
@ -3497,6 +3497,8 @@ var PermissionsHelper = {
var MasterPassword = {
pref: "privacy.masterpassword.enabled",
_tokenName: "",
get _secModuleDB() {
delete this._secModuleDB;
return this._secModuleDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(Ci.nsIPKCS11ModuleDB);

Просмотреть файл

@ -1,18 +1,12 @@
<!ENTITY aboutPage.title "About &brandShortName;">
<!ENTITY aboutPage.checkForUpdates.link "Check for Updates »">
<!ENTITY aboutPage.checkForUpdates.checking "Looking for updates…">
<!ENTITY aboutPage.checkForUpdates.none "No updates available">
<!ENTITY aboutPage.checkForUpdates.found "Update available">
<!ENTITY aboutPage.faq.label "FAQ">
<!ENTITY aboutPage.support.label "Support">
<!ENTITY aboutPage.privacyPolicy.label "Privacy Policy">
<!ENTITY aboutPage.rights.label "Know Your Rights">
<!ENTITY aboutPage.relNotes.label "Release Notes">
<!ENTITY aboutPage.credits.label "Credits">
<!ENTITY aboutPage.checkForUpdates.link "Check for Updates »">
<!ENTITY aboutPage.checkForUpdates.checking "Looking for updates…">
<!ENTITY aboutPage.checkForUpdates.none "No updates available">
<!ENTITY aboutPage.checkForUpdates.found "Update available">
<!-- LOCALIZATION NOTE:
These strings are concatenated in order. Unneeded strings may be left blank.
-->
<!ENTITY aboutPage.licenseLink "Licensing information">
<!ENTITY aboutPage.licenseLinkSuffix ".">
<!ENTITY aboutPage.license.label "Licensing Information">

Просмотреть файл

@ -103,7 +103,7 @@ body {
}
#aboutLinks > li {
line-height: 3;
line-height: 2.6;
border-top: 1px solid white;
border-bottom: 1px solid #C1C7CC;
}

Просмотреть файл

@ -1,24 +1,27 @@
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><span class="doctype">&lt;!DOCTYPE html&gt;</span>
<span>&lt;<span class="start-tag">html</span>&gt;</span>
<span>&lt;<span class="start-tag">head</span>&gt;</span>
<span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span>&lt;<span class="start-tag">script</span>&gt;</span>
var lt = "&lt;";
&lt;!--
var s = "&lt;script&gt;foo&lt;/script&gt;";
--&gt;
<span class="end-tag">&lt;/script&gt;</span><span></span><span class="comment">&lt;!-- Not quite optimal highlight there. --&gt;</span>
<span>&lt;<span class="start-tag">style</span>&gt;</span>
/* &lt;/foo&gt; */
<span>&lt;/<span class="end-tag">style</span>&gt;</span>
<span>&lt;/<span class="end-tag">head</span>&gt;</span>
<span>&lt;<span class="start-tag">body</span>&gt;</span>
<span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
<span>&lt;<span class="start-tag">iframe</span>&gt;</span>&lt;img&gt;<span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
<span>&lt;<span class="start-tag">noscript</span>&gt;</span>&lt;p&gt;Not para&lt;/p&gt;<span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
<span>&lt;<span class="start-tag">svg</span>&gt;</span>
<span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
<span>&lt;/<span class="end-tag">svg</span>&gt;</span>
<span>&lt;/<span class="end-tag">body</span>&gt;</span>
<span>&lt;/<span class="end-tag">html</span>&gt;</span>
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><pre id><span class="doctype">&lt;!DOCTYPE html&gt;</span>
<span id></span><span>&lt;<span class="start-tag">html</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">head</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span>
<span id></span>var lt = "&lt;";
<span id></span>&lt;!--
<span id></span>var s = "&lt;script&gt;foo&lt;/script&gt;";
<span id></span>--&gt;
<span id></span><span class="end-tag">&lt;/script&gt;</span><span></span><span class="comment">&lt;!-- Not quite optimal highlight there. --&gt;</span>
<span id></span><span>&lt;<span class="start-tag">style</span>&gt;</span>
<span id></span>/* &lt;/foo&gt; */
<span id></span><span>&lt;/<span class="end-tag">style</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">head</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">body</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">iframe</span>&gt;</span>&lt;img&gt;<span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">noscript</span>&gt;</span>&lt;p&gt;Not para&lt;/p&gt;<span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">svg</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">svg</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">body</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">html</span>&gt;</span>
<span id></span>
</pre>
<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->

Просмотреть файл

@ -1,25 +1,28 @@
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><span class="pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="pi">&lt;?foo bar?&gt;</span>
<span>&lt;<span class="start-tag">html</span>&gt;</span>
<span>&lt;<span class="start-tag">head</span>&gt;</span>
<span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span>&lt;<span class="start-tag">script</span>&gt;</span>
var s = "<span>&lt;<span class="start-tag">script</span>&gt;</span><span>foo</span><span>&lt;/<span class="end-tag">script</span>&gt;</span>";
<span class="comment">&lt;!--
var s = "&lt;script&gt;foo&lt;/script&gt;";
--&gt;</span>
<span>&lt;/<span class="end-tag">script</span>&gt;</span><span></span>
<span>&lt;<span class="start-tag">style</span>&gt;</span>
/* <span>&lt;<span class="start-tag">foo</span><span>/</span>&gt;</span> */
<span>&lt;/<span class="end-tag">style</span>&gt;</span>
<span>&lt;/<span class="end-tag">head</span>&gt;</span>
<span>&lt;<span class="start-tag">body</span>&gt;</span>
<span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
<span>&lt;<span class="start-tag">iframe</span>&gt;</span><span></span><span>&lt;<span class="start-tag">img</span>&gt;</span><span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
<span>&lt;<span class="start-tag">noscript</span>&gt;</span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Not para</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
<span>&lt;<span class="start-tag">svg</span>&gt;</span>
<span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
<span>&lt;/<span class="end-tag">svg</span>&gt;</span>
<span>&lt;/<span class="end-tag">body</span>&gt;</span>
<span>&lt;/<span class="end-tag">html</span>&gt;</span>
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><pre id><span class="pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span id></span><span class="pi">&lt;?foo bar?&gt;</span>
<span id></span><span>&lt;<span class="start-tag">html</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">head</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span>Title</span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span>
<span id></span>var s = "<span>&lt;<span class="start-tag">script</span>&gt;</span><span>foo</span><span>&lt;/<span class="end-tag">script</span>&gt;</span>";
<span id></span><span class="comment">&lt;!--
<span id></span>var s = "&lt;script&gt;foo&lt;/script&gt;";
<span id></span>--&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">script</span>&gt;</span><span></span>
<span id></span><span>&lt;<span class="start-tag">style</span>&gt;</span>
<span id></span>/* <span>&lt;<span class="start-tag">foo</span><span>/</span>&gt;</span> */
<span id></span><span>&lt;/<span class="end-tag">style</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">head</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">body</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Entity: <span class="entity"><span>&amp;</span>amp; </span></span><span>&lt;/<span class="end-tag">p</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">iframe</span>&gt;</span><span></span><span>&lt;<span class="start-tag">img</span>&gt;</span><span>&lt;/<span class="end-tag">iframe</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">noscript</span>&gt;</span><span>&lt;<span class="start-tag">p</span>&gt;</span><span>Not para</span><span>&lt;/<span class="end-tag">p</span>&gt;</span><span>&lt;/<span class="end-tag">noscript</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">svg</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">title</span>&gt;</span><span></span><span class="cdata">&lt;![CDATA[bar]]&gt;</span><span></span><span>&lt;/<span class="end-tag">title</span>&gt;</span>
<span id></span><span>&lt;<span class="start-tag">script</span>&gt;</span><span></span><span class="comment">&lt;!-- this is a comment --&gt;</span><span></span><span>&lt;/<span class="end-tag">script</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">svg</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">body</span>&gt;</span>
<span id></span><span>&lt;/<span class="end-tag">html</span>&gt;</span>
<span id></span>
</pre>
<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->

Просмотреть файл

@ -1,13 +1,17 @@
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><span class="doctype">&lt;!DOCTYPE html&gt;</span>
XX<span class="error">&amp;</span>XX
XX<span class="error">&amp;</span>nXX
XX<span class="error">&amp;</span>noXX
XX<span class="error entity">&amp;not</span>XX
XX<span class="error entity">&amp;noti</span>XX
XX<span class="error entity">&amp;notin</span>XX
XX<span class="error">&amp;</span>;XX
XX<span class="error">&amp;</span>n;XX
XX<span class="error">&amp;</span>no;XX
XX<span class="entity">&amp;not;</span>XX
XX<span class="error entity">&amp;noti</span>;XX
XX<span class="entity">&amp;notin;</span>XX
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><pre id><span class="doctype">&lt;!DOCTYPE html&gt;</span>
<span id></span>XX<span class="error">&amp;</span>XX
<span id></span>XX<span class="error">&amp;</span>nXX
<span id></span>XX<span class="error">&amp;</span>noXX
<span id></span>XX<span class="error entity">&amp;not</span>XX
<span id></span>XX<span class="error entity">&amp;noti</span>XX
<span id></span>XX<span class="error entity">&amp;notin</span>XX
<span id></span>XX<span class="error">&amp;</span>;XX
<span id></span>XX<span class="error">&amp;</span>n;XX
<span id></span>XX<span class="error">&amp;</span>no;XX
<span id></span>XX<span class="entity">&amp;not;</span>XX
<span id></span>XX<span class="error entity">&amp;noti</span>;XX
<span id></span>XX<span class="entity">&amp;notin;</span>XX
<span id></span>
<span id></span>
</pre>
<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->

Просмотреть файл

@ -1 +1,4 @@
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><span class="error comment">&lt;!--&gt;</span> <span class="error comment">&lt;!X&gt;</span>
<!DOCTYPE html><html><head><title></title><link rel="stylesheet" type="text/css" href="resource://gre-resources/viewsource.css"></head><body id="viewsource" class="wrap"><pre id><span class="error comment">&lt;!--&gt;</span> <span class="error comment">&lt;!X&gt;</span>
<span id></span>
</pre>
<!-- View source CSS matches the <pre id> and <span id> elements and produces line numbers. -->

Просмотреть файл

@ -1,5 +1,5 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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
@ -11,7 +11,7 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mochitest Reusable Mock File Picker.
* The Original Code is Reusable Mock File Picker.
*
* The Initial Developer of the Original Code is
* Geoff Lankow <geoff@darktrojan.net>.
@ -20,6 +20,18 @@
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var EXPORTED_SYMBOLS = ["MockFilePicker"];
@ -30,15 +42,15 @@ const Cm = Components.manager;
const Cu = Components.utils;
const CONTRACT_ID = "@mozilla.org/filepicker;1";
const CLASS_ID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
var MockFilePickerFactory = {
var oldClassID, oldFactory;
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
var newFactory = {
createInstance: function(aOuter, aIID) {
if (aOuter)
throw Components.results.NS_ERROR_NO_AGGREGATION;
@ -66,6 +78,16 @@ var MockFilePicker = {
filterAudio: Ci.nsIFilePicker.filterAudio,
filterVideo: Ci.nsIFilePicker.filterVideo,
init: function() {
this.reset();
if (!registrar.isCIDRegistered(newClassID)) {
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
registrar.unregisterFactory(oldClassID, oldFactory);
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
}
},
reset: function() {
this.appendFilterCallback = null;
this.appendFiltersCallback = null;
@ -76,8 +98,14 @@ var MockFilePicker = {
this.returnValue = null;
this.showCallback = null;
this.shown = false;
if (!registrar.isCIDRegistered(CLASS_ID))
registrar.registerFactory(CLASS_ID, "", CONTRACT_ID, MockFilePickerFactory);
},
cleanup: function() {
this.reset();
if (oldFactory) {
registrar.unregisterFactory(newClassID, newFactory);
registrar.registerFactory(oldClassID, "", CONTRACT_ID, oldFactory);
}
},
useAnyFile: function() {
@ -131,8 +159,11 @@ MockFilePickerInstance.prototype = {
show: function() {
MockFilePicker.displayDirectory = this.displayDirectory;
MockFilePicker.shown = true;
if (typeof MockFilePicker.showCallback == "function")
MockFilePicker.showCallback(this);
if (typeof MockFilePicker.showCallback == "function") {
var returnValue = MockFilePicker.showCallback(this);
if (typeof returnValue != "undefined")
return returnValue;
}
return MockFilePicker.returnValue;
}
};

Просмотреть файл

@ -1,7 +1,10 @@
This is the git repo for the mozbase suite of python utilities.
This is the git repo for the Mozilla mozbase suite of python utilities.
Learn more about mozbase here: https://wiki.mozilla.org/Auto-tools/Projects/MozBase
Learn more about mozbase here:
https://wiki.mozilla.org/Auto-tools/Projects/MozBase
Bugs live at https://bugzilla.mozilla.org/buglist.cgi?resolution=---&component=Mozbase&product=Testing and https://bugzilla.mozilla.org/buglist.cgi?resolution=---&status_whiteboard_type=allwordssubstr&query_format=advanced&status_whiteboard=mozbase
Bugs live at
https://bugzilla.mozilla.org/buglist.cgi?resolution=---&component=Mozbase&product=Testing and https://bugzilla.mozilla.org/buglist.cgi?resolution=---&status_whiteboard_type=allwordssubstr&query_format=advanced&status_whiteboard=mozbase
To file a bug, go to https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=Mozbase
To file a bug, go to
https://bugzilla.mozilla.org/enter_bug.cgi?product=Testing&component=Mozbase

Просмотреть файл

@ -0,0 +1,9 @@
#!/usr/bin/env document-it
# documentation manifest for the Mozbase repo
# To generate HTML from this markdown, use document_it:
# http://pypi.python.org/pypi/document_it
mozinfo/README.md en/Mozinfo
mozprocess/README.md en/Mozprocess
mozprofile/README.md en/Mozprofile
mozrunner/README.md en/Mozrunner

Просмотреть файл

@ -10,11 +10,11 @@ What ManifestDestiny gives you:
are just dicts with some keys. For example, a test with no
user-specified metadata looks like this:
[{'path':
'/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests/testToolbar/testBackForwardButtons.js',
'name': 'testToolbar/testBackForwardButtons.js', 'here':
'/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',
'manifest': '/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',}]
[{'path':
'/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests/testToolbar/testBackForwardButtons.js',
'name': 'testToolbar/testBackForwardButtons.js', 'here':
'/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',
'manifest': '/home/jhammel/mozmill/src/ManifestDestiny/manifestdestiny/tests',}]
The keys displayed here (path, name, here, and manifest) are reserved
keys for ManifestDestiny and any consuming APIs. You can add

Просмотреть файл

@ -170,12 +170,18 @@ def _install_dmg(src, dest):
if appFile.endswith(".app"):
appName = appFile
break
subprocess.call("cp -r " + os.path.join(appDir, appName) + " " + dest,
dest = os.path.join(dest, appName)
assert not os.path.isfile(dest)
if not os.path.isdir(dest):
os.makedirs(dest)
subprocess.call("cp -r " +
os.path.join(appDir,appName, "*") + " " + dest,
shell=True)
finally:
subprocess.call("hdiutil detach " + appDir + " -quiet",
shell=True)
return os.path.join(dest, appName)
return dest
def _install_exe(src, dest):
# possibly gets around UAC in vista (still need to run as administrator)

Просмотреть файл

@ -46,6 +46,7 @@ import subprocess
import sys
import threading
import time
import traceback
from Queue import Queue
from datetime import datetime, timedelta
@ -111,7 +112,10 @@ class ProcessHandlerMixin(object):
def __del__(self, _maxint=sys.maxint):
if mozinfo.isWin:
if self._handle:
self._internal_poll(_deadstate=_maxint)
if hasattr(self, '_internal_poll'):
self._internal_poll(_deadstate=_maxint)
else:
self.poll(_deadstate=sys.maxint)
if self._handle or self._job or self._io_port:
self._cleanup()
else:
@ -257,13 +261,15 @@ class ProcessHandlerMixin(object):
except:
print >> sys.stderr, """Exception trying to use job objects;
falling back to not using job objects for managing child processes"""
tb = traceback.format_exc()
print >> sys.stderr, tb
# Ensure no dangling handles left behind
self._cleanup_job_io_port()
else:
self._job = None
winprocess.ResumeThread(int(ht))
if self._procmgrthread:
if getattr(self, '_procmgrthread', None):
self._procmgrthread.start()
ht.Close()
@ -373,7 +379,13 @@ falling back to not using job objects for managing child processes"""
# Dude, the process is like totally dead!
return self.returncode
if self._job and self._procmgrthread.is_alive():
# Python 2.5 uses isAlive versus is_alive use the proper one
threadalive = False
if hasattr(self._procmgrthread, 'is_alive'):
threadalive = self._procmgrthread.is_alive()
else:
threadalive = self._procmgrthread.isAlive()
if self._job and threadalive:
# Then we are managing with IO Completion Ports
# wait on a signal so we know when we have seen the last
# process come through.
@ -429,7 +441,7 @@ falling back to not using job objects for managing child processes"""
cases where we want to clean these without killing _handle
(i.e. if we fail to create the job object in the first place)
"""
if self._job and self._job != winprocess.INVALID_HANDLE_VALUE:
if getattr(self, '_job') and self._job != winprocess.INVALID_HANDLE_VALUE:
self._job.Close()
self._job = None
else:
@ -437,13 +449,13 @@ falling back to not using job objects for managing child processes"""
# (saw this intermittently while testing)
self._job = None
if self._io_port and self._io_port != winprocess.INVALID_HANDLE_VALUE:
if getattr(self, '_io_port', None) and self._io_port != winprocess.INVALID_HANDLE_VALUE:
self._io_port.Close()
self._io_port = None
else:
self._io_port = None
if self._procmgrthread:
if getattr(self, '_procmgrthread', None):
self._procmgrthread = None
def _cleanup(self):

Просмотреть файл

@ -255,7 +255,7 @@ CreateIoCompletionPortProto = WINFUNCTYPE(HANDLE, # Return Type
DWORD # Number of Threads
)
CreateIoCompletionPortFlags = ((1, "FileHandle", INVALID_HANDLE_VALUE),
(1, "ExistingCompletionPort", None),
(1, "ExistingCompletionPort", 0),
(1, "CompletionKey", c_ulong(0)),
(1, "NumberOfConcurrentThreads", 0))
CreateIoCompletionPort = CreateIoCompletionPortProto(("CreateIoCompletionPort",

Просмотреть файл

@ -56,8 +56,8 @@ setup(name='mozprocess',
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='',
author='Mozilla Automation and Testing Team',
author_email='mozmill-dev@googlegroups.com',
url='http://github.com/mozautomation/mozmill',
author_email='tools@lists.mozilla.com',
url='https://github.com/mozilla/mozbase/tree/master/mozprocess',
license='MPL',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
include_package_data=True,

Просмотреть файл

@ -0,0 +1,57 @@
#
# proclaunch tests Makefile
#
UNAME := $(shell uname -s)
ifeq ($(UNAME), MINGW32_NT-6.1)
WIN32 = 1
endif
ifeq ($(UNAME), MINGW32_NT-5.1)
WIN32 = 1
endif
ifeq ($(WIN32), 1)
CC = cl
LINK = link
CFLAGS = //Od //I "iniparser" //D "WIN32" //D "_WIN32" //D "_DEBUG" //D "_CONSOLE" //D "_UNICODE" //D "UNICODE" //Gm //EHsc //RTC1 //MDd //W3 //nologo //c //ZI //TC
LFLAGS = //OUT:"proclaunch.exe" //INCREMENTAL //LIBPATH:"iniparser\\" //NOLOGO //DEBUG //SUBSYSTEM:CONSOLE //DYNAMICBASE //NXCOMPAT //MACHINE:X86 //ERRORREPORT:PROMPT iniparser.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
RM = rm -f
default: all
all: iniparser proclaunch
iniparser:
$(MAKE) -C iniparser
proclaunch.obj: proclaunch.c
$(CC) $(CFLAGS) proclaunch.c
proclaunch: proclaunch.obj
$(LINK) $(LFLAGS) proclaunch.obj
else
CC = gcc
ifeq ($(UNAME), Linux)
CFLAGS = -g -v -Iiniparser
else
CFLAGS = -g -v -arch i386 -Iiniparser
endif
LFLAGS = -L.. -liniparser
AR = ar
ARFLAGS = rcv
RM = rm -f
default: all
all: libiniparser.a proclaunch
libiniparser.a:
$(MAKE) -C iniparser
proclaunch: proclaunch.c
$(CC) $(CFLAGS) -o proclaunch proclaunch.c -Iiniparser -Liniparser -liniparser
clean veryclean:
$(RM) proclaunch
endif

Просмотреть файл

@ -0,0 +1,6 @@
Author: Nicolas Devillard <ndevilla@free.fr>
This tiny library has received countless contributions and I have
not kept track of all the people who contributed. Let them be thanked
for their ideas, code, suggestions, corrections, enhancements!

Просмотреть файл

@ -0,0 +1,15 @@
iniParser installation instructions
-----------------------------------
- Modify the Makefile to suit your environment.
- Type 'make' to make the library.
- Type 'make check' to make the test program.
- Type 'test/iniexample' to launch the test program.
- Type 'test/parse' to launch torture tests.
Enjoy!
N. Devillard
Wed Mar 2 21:14:17 CET 2011

Просмотреть файл

@ -0,0 +1,21 @@
Copyright (c) 2000-2011 by Nicolas Devillard.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

Просмотреть файл

@ -0,0 +1,118 @@
#
# iniparser Makefile
#
UNAME := $(shell uname -s)
ifeq ($(UNAME), MINGW32_NT-6.1)
WIN32 = 1
endif
ifeq ($(UNAME), MINGW32_NT-5.1)
WIN32 = 1
endif
ifeq ($(UNAME), Linux)
# Compiler settings
CC = gcc
# Ar settings to build the library
AR = ar
ARFLAGS = rcv
SHLD = ${CC} ${CFLAGS}
CFLAGS = -O2 -fPIC -Wall -ansi -pedantic
LDSHFLAGS = -shared -Wl,-Bsymbolic -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
LDFLAGS = -Wl,-rpath -Wl,/usr/lib -Wl,-rpath,/usr/lib
endif
ifeq ($(UNAME), Darwin)
# Compiler settings
CC = gcc
# Ar settings to build the library
AR = ar
ARFLAGS = rcv
#SHLD = ${CC} ${CFLAGS}
SHLD = libtool
CFLAGS = -v -arch i386 -isysroot /Developer/SDKs/MacOSX10.6.sdk -fPIC -Wall -ansi -pedantic
LDFLAGS = -arch_only i386
endif
ifeq ($(WIN32), 1)
CC = cl
CFLAGS = //Od //D "_WIN32" //D "WIN32" //D "_CONSOLE" //D "_CRT_SECURE_NO_WARNINGS" //D "_UNICODE" //D "UNICODE" //Gm //EHsc //RTC1 //MDd //W3 //nologo //c //ZI //TC
LDFLAGS = //OUT:"iniparser.lib" //NOLOGO
LINK = lib
endif
ifeq ($(WIN32), 1)
SUFFIXES = .obj .c .h .lib
COMPILE.c=$(CC) $(CFLAGS) -c
#.c.obj:
# @(echo "compiling $< ...")
# @($(COMPILE.c) $@ $<)
all: iniparser.obj dictionary.obj iniparser.lib
SRCS = iniparser.c \
dictionary.c
OBJS = $(SRCS:.c=.obj)
iniparser.obj: dictionary.obj
@($(CC) $(CFLAGS) iniparser.c)
dictionary.obj:
@($(CC) $(CFLAGS) dictionary.c)
iniparser.lib: dictionary.obj iniparser.obj
@(echo "linking $(OBJS)")
@($(LINK) $(LDFLAGS) $(OBJS))
else
# Set RANLIB to ranlib on systems that require it (Sun OS < 4, Mac OSX)
# RANLIB = ranlib
RANLIB = true
RM = rm -f
# Implicit rules
SUFFIXES = .o .c .h .a .so .sl
COMPILE.c=$(CC) $(CFLAGS) -c
.c.o:
@(echo "compiling $< ...")
@($(COMPILE.c) -o $@ $<)
SRCS = iniparser.c \
dictionary.c
OBJS = $(SRCS:.c=.o)
default: libiniparser.a libiniparser.so
libiniparser.a: $(OBJS)
@($(AR) $(ARFLAGS) libiniparser.a $(OBJS))
@($(RANLIB) libiniparser.a)
ifeq ($(UNAME), Linux)
libiniparser.so: $(OBJS)
@$(SHLD) $(LDSHFLAGS) -o $@.0 $(OBJS) $(LDFLAGS)
else
libiniparser.so: $(OBJS)
@$(SHLD) -o $@.0 $(LDFLAGS) $(OBJS)
endif
endif
clean:
$(RM) $(OBJS)
veryclean:
$(RM) $(OBJS) libiniparser.a libiniparser.so*
rm -rf ./html ; mkdir html
cd test ; $(MAKE) veryclean
docs:
@(cd doc ; $(MAKE))
check:
@(cd test ; $(MAKE))

Просмотреть файл

@ -0,0 +1,12 @@
Welcome to iniParser -- version 3.0
released 02 Mar 2011
This modules offers parsing of ini files from the C level.
See a complete documentation in HTML format, from this directory
open the file html/index.html with any HTML-capable browser.
Enjoy!
N.Devillard
Wed Mar 2 21:46:14 CET 2011

Просмотреть файл

@ -0,0 +1,407 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.c
@author N. Devillard
@date Sep 2007
@version $Revision: 1.27 $
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
/*
$Id: dictionary.c,v 1.27 2007-11-23 21:39:18 ndevilla Exp $
$Revision: 1.27 $
*/
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include "dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
/** Maximum value size for integers and doubles. */
#define MAXVALSZ 1024
/** Minimal allocated number of entries in a dictionary */
#define DICTMINSZ 128
/** Invalid key token */
#define DICT_INVALID_KEY ((char*)-1)
/*---------------------------------------------------------------------------
Private functions
---------------------------------------------------------------------------*/
/* Doubles the allocated size associated to a pointer */
/* 'size' is the current allocated size. */
static void * mem_double(void * ptr, int size)
{
void * newptr ;
newptr = calloc(2*size, 1);
if (newptr==NULL) {
return NULL ;
}
memcpy(newptr, ptr, size);
free(ptr);
return newptr ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Duplicate a string
@param s String to duplicate
@return Pointer to a newly allocated string, to be freed with free()
This is a replacement for strdup(). This implementation is provided
for systems that do not have it.
*/
/*--------------------------------------------------------------------------*/
static char * xstrdup(char * s)
{
char * t ;
if (!s)
return NULL ;
t = malloc(strlen(s)+1) ;
if (t) {
strcpy(t,s);
}
return t ;
}
/*---------------------------------------------------------------------------
Function codes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(char * key)
{
int len ;
unsigned hash ;
int i ;
len = strlen(key);
for (hash=0, i=0 ; i<len ; i++) {
hash += (unsigned)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary objet.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(int size)
{
dictionary * d ;
/* If no size was specified, allocate space for DICTMINSZ */
if (size<DICTMINSZ) size=DICTMINSZ ;
if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
return NULL;
}
d->size = size ;
d->val = (char **)calloc(size, sizeof(char*));
d->key = (char **)calloc(size, sizeof(char*));
d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
return d ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * d)
{
int i ;
if (d==NULL) return ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]!=NULL)
free(d->key[i]);
if (d->val[i]!=NULL)
free(d->val[i]);
}
free(d->val);
free(d->key);
free(d->hash);
free(d);
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, char * key, char * def)
{
unsigned hash ;
int i ;
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
return d->val[i] ;
}
}
}
return def ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * d, char * key, char * val)
{
int i ;
unsigned hash ;
if (d==NULL || key==NULL) return -1 ;
/* Compute hash for this key */
hash = dictionary_hash(key) ;
/* Find if value is already in dictionary */
if (d->n>0) {
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (hash==d->hash[i]) { /* Same hash value */
if (!strcmp(key, d->key[i])) { /* Same key */
/* Found a value: modify and return */
if (d->val[i]!=NULL)
free(d->val[i]);
d->val[i] = val ? xstrdup(val) : NULL ;
/* Value has been modified: return */
return 0 ;
}
}
}
}
/* Add a new value */
/* See if dictionary needs to grow */
if (d->n==d->size) {
/* Reached maximum size: reallocate dictionary */
d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
/* Cannot grow dictionary */
return -1 ;
}
/* Double size */
d->size *= 2 ;
}
/* Insert key in the first empty slot */
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL) {
/* Add key here */
break ;
}
}
/* Copy key */
d->key[i] = xstrdup(key);
d->val[i] = val ? xstrdup(val) : NULL ;
d->hash[i] = hash;
d->n ++ ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, char * key)
{
unsigned hash ;
int i ;
if (key == NULL) {
return;
}
hash = dictionary_hash(key);
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
/* Compare hash */
if (hash==d->hash[i]) {
/* Compare string, to avoid hash collisions */
if (!strcmp(key, d->key[i])) {
/* Found key */
break ;
}
}
}
if (i>=d->size)
/* Key not found */
return ;
free(d->key[i]);
d->key[i] = NULL ;
if (d->val[i]!=NULL) {
free(d->val[i]);
d->val[i] = NULL ;
}
d->hash[i] = 0 ;
d->n -- ;
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out)
{
int i ;
if (d==NULL || out==NULL) return ;
if (d->n<1) {
fprintf(out, "empty dictionary\n");
return ;
}
for (i=0 ; i<d->size ; i++) {
if (d->key[i]) {
fprintf(out, "%20s\t[%s]\n",
d->key[i],
d->val[i] ? d->val[i] : "UNDEF");
}
}
return ;
}
/* Test code */
#ifdef TESTDIC
#define NVALS 20000
int main(int argc, char *argv[])
{
dictionary * d ;
char * val ;
int i ;
char cval[90] ;
/* Allocate dictionary */
printf("allocating...\n");
d = dictionary_new(0);
/* Set values in dictionary */
printf("setting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_set(d, cval, "salut");
}
printf("getting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
val = dictionary_get(d, cval, DICT_INVALID_KEY);
if (val==DICT_INVALID_KEY) {
printf("cannot get value for key [%s]\n", cval);
}
}
printf("unsetting %d values...\n", NVALS);
for (i=0 ; i<NVALS ; i++) {
sprintf(cval, "%04d", i);
dictionary_unset(d, cval);
}
if (d->n != 0) {
printf("error deleting values\n");
}
printf("deallocating...\n");
dictionary_del(d);
return 0 ;
}
#endif
/* vim: set ts=4 et sw=4 tw=75 */

Просмотреть файл

@ -0,0 +1,176 @@
/*-------------------------------------------------------------------------*/
/**
@file dictionary.h
@author N. Devillard
@date Sep 2007
@version $Revision: 1.12 $
@brief Implements a dictionary for string variables.
This module implements a simple dictionary object, i.e. a list
of string/string associations. This object is useful to store e.g.
informations retrieved from a configuration file (ini files).
*/
/*--------------------------------------------------------------------------*/
/*
$Id: dictionary.h,v 1.12 2007-11-23 21:37:00 ndevilla Exp $
$Author: ndevilla $
$Date: 2007-11-23 21:37:00 $
$Revision: 1.12 $
*/
#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
/*---------------------------------------------------------------------------
New types
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Dictionary object
This object contains a list of string/string associations. Each
association is identified by a unique string key. Looking up values
in the dictionary is speeded up by the use of a (hopefully collision-free)
hash function.
*/
/*-------------------------------------------------------------------------*/
typedef struct _dictionary_ {
int n ; /** Number of entries in dictionary */
int size ; /** Storage size */
char ** val ; /** List of string values */
char ** key ; /** List of string keys */
unsigned * hash ; /** List of hash values for keys */
} dictionary ;
/*---------------------------------------------------------------------------
Function prototypes
---------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/**
@brief Compute the hash key for a string.
@param key Character string to use for key.
@return 1 unsigned int on at least 32 bits.
This hash function has been taken from an Article in Dr Dobbs Journal.
This is normally a collision-free function, distributing keys evenly.
The key is stored anyway in the struct so that collision can be avoided
by comparing the key itself in last resort.
*/
/*--------------------------------------------------------------------------*/
unsigned dictionary_hash(char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Create a new dictionary object.
@param size Optional initial size of the dictionary.
@return 1 newly allocated dictionary objet.
This function allocates a new dictionary object of given size and returns
it. If you do not know in advance (roughly) the number of entries in the
dictionary, give size=0.
*/
/*--------------------------------------------------------------------------*/
dictionary * dictionary_new(int size);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a dictionary object
@param d dictionary object to deallocate.
@return void
Deallocate a dictionary object and all memory associated to it.
*/
/*--------------------------------------------------------------------------*/
void dictionary_del(dictionary * vd);
/*-------------------------------------------------------------------------*/
/**
@brief Get a value from a dictionary.
@param d dictionary object to search.
@param key Key to look for in the dictionary.
@param def Default value to return if key not found.
@return 1 pointer to internally allocated character string.
This function locates a key in a dictionary and returns a pointer to its
value, or the passed 'def' pointer if no such key can be found in
dictionary. The returned character pointer points to data internal to the
dictionary object, you should not try to free it or modify it.
*/
/*--------------------------------------------------------------------------*/
char * dictionary_get(dictionary * d, char * key, char * def);
/*-------------------------------------------------------------------------*/
/**
@brief Set a value in a dictionary.
@param d dictionary object to modify.
@param key Key to modify or add.
@param val Value to add.
@return int 0 if Ok, anything else otherwise
If the given key is found in the dictionary, the associated value is
replaced by the provided one. If the key cannot be found in the
dictionary, it is added to it.
It is Ok to provide a NULL value for val, but NULL values for the dictionary
or the key are considered as errors: the function will return immediately
in such a case.
Notice that if you dictionary_set a variable to NULL, a call to
dictionary_get will return a NULL value: the variable will be found, and
its value (NULL) is returned. In other words, setting the variable
content to NULL is equivalent to deleting the variable from the
dictionary. It is not possible (in this implementation) to have a key in
the dictionary without value.
This function returns non-zero in case of failure.
*/
/*--------------------------------------------------------------------------*/
int dictionary_set(dictionary * vd, char * key, char * val);
/*-------------------------------------------------------------------------*/
/**
@brief Delete a key in a dictionary
@param d dictionary object to modify.
@param key Key to remove.
@return void
This function deletes a key in a dictionary. Nothing is done if the
key cannot be found.
*/
/*--------------------------------------------------------------------------*/
void dictionary_unset(dictionary * d, char * key);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump
@param f Opened file pointer.
@return void
Dumps a dictionary onto an opened file pointer. Key pairs are printed out
as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as
output file pointers.
*/
/*--------------------------------------------------------------------------*/
void dictionary_dump(dictionary * d, FILE * out);
#endif

Просмотреть файл

@ -0,0 +1,648 @@
/*-------------------------------------------------------------------------*/
/**
@file iniparser.c
@author N. Devillard
@date Sep 2007
@version 3.0
@brief Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: iniparser.c,v 2.19 2011-03-02 20:15:13 ndevilla Exp $
$Revision: 2.19 $
$Date: 2011-03-02 20:15:13 $
*/
/*---------------------------- Includes ------------------------------------*/
#include <ctype.h>
#include "iniparser.h"
/*---------------------------- Defines -------------------------------------*/
#define ASCIILINESZ (1024)
#define INI_INVALID_KEY ((char*)-1)
/*---------------------------------------------------------------------------
Private to this module
---------------------------------------------------------------------------*/
/**
* This enum stores the status for each parsed line (internal use only).
*/
typedef enum _line_status_ {
LINE_UNPROCESSED,
LINE_ERROR,
LINE_EMPTY,
LINE_COMMENT,
LINE_SECTION,
LINE_VALUE
} line_status ;
/*-------------------------------------------------------------------------*/
/**
@brief Convert a string to lowercase.
@param s String to convert.
@return ptr to statically allocated string.
This function returns a pointer to a statically allocated string
containing a lowercased version of the input string. Do not free
or modify the returned string! Since the returned string is statically
allocated, it will be modified at each function call (not re-entrant).
*/
/*--------------------------------------------------------------------------*/
static char * strlwc(char * s)
{
static char l[ASCIILINESZ+1];
int i ;
if (s==NULL) return NULL ;
memset(l, 0, ASCIILINESZ+1);
i=0 ;
while (s[i] && i<ASCIILINESZ) {
l[i] = (char)tolower((int)s[i]);
i++ ;
}
l[ASCIILINESZ]=(char)0;
return l ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Remove blanks at the beginning and the end of a string.
@param s String to parse.
@return ptr to statically allocated string.
This function returns a pointer to a statically allocated string,
which is identical to the input string, except that all blank
characters at the end and the beg. of the string have been removed.
Do not free or modify the returned string! Since the returned string
is statically allocated, it will be modified at each function call
(not re-entrant).
*/
/*--------------------------------------------------------------------------*/
static char * strstrip(char * s)
{
static char l[ASCIILINESZ+1];
char * last ;
if (s==NULL) return NULL ;
while (isspace((int)*s) && *s) s++;
memset(l, 0, ASCIILINESZ+1);
strcpy(l, s);
last = l + strlen(l);
while (last > l) {
if (!isspace((int)*(last-1)))
break ;
last -- ;
}
*last = (char)0;
return (char*)l ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get number of sections in a dictionary
@param d Dictionary to examine
@return int Number of sections found in dictionary
This function returns the number of sections found in a dictionary.
The test to recognize sections is done on the string stored in the
dictionary: a section name is given as "section" whereas a key is
stored as "section:key", thus the test looks for entries that do not
contain a colon.
This clearly fails in the case a section name contains a colon, but
this should simply be avoided.
This function returns -1 in case of error.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d)
{
int i ;
int nsec ;
if (d==NULL) return -1 ;
nsec=0 ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (strchr(d->key[i], ':')==NULL) {
nsec ++ ;
}
}
return nsec ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get name for section n in a dictionary.
@param d Dictionary to examine
@param n Section number (from 0 to nsec-1).
@return Pointer to char string
This function locates the n-th section in a dictionary and returns
its name as a pointer to a string statically allocated inside the
dictionary. Do not free or modify the returned string!
This function returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n)
{
int i ;
int foundsec ;
if (d==NULL || n<0) return NULL ;
foundsec=0 ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (strchr(d->key[i], ':')==NULL) {
foundsec++ ;
if (foundsec>n)
break ;
}
}
if (foundsec<=n) {
return NULL ;
}
return d->key[i] ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump.
@param f Opened file pointer to dump to.
@return void
This function prints out the contents of a dictionary, one element by
line, onto the provided file pointer. It is OK to specify @c stderr
or @c stdout as output files. This function is meant for debugging
purposes mostly.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary * d, FILE * f)
{
int i ;
if (d==NULL || f==NULL) return ;
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
if (d->val[i]!=NULL) {
fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);
} else {
fprintf(f, "[%s]=UNDEF\n", d->key[i]);
}
}
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary to a loadable ini file
@param d Dictionary to dump
@param f Opened file pointer to dump to
@return void
This function dumps a given dictionary into a loadable ini file.
It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary * d, FILE * f)
{
int i, j ;
char keym[ASCIILINESZ+1];
int nsec ;
char * secname ;
int seclen ;
if (d==NULL || f==NULL) return ;
nsec = iniparser_getnsec(d);
if (nsec<1) {
/* No section in file: dump all keys as they are */
for (i=0 ; i<d->size ; i++) {
if (d->key[i]==NULL)
continue ;
fprintf(f, "%s = %s\n", d->key[i], d->val[i]);
}
return ;
}
for (i=0 ; i<nsec ; i++) {
secname = iniparser_getsecname(d, i) ;
seclen = (int)strlen(secname);
fprintf(f, "\n[%s]\n", secname);
sprintf(keym, "%s:", secname);
for (j=0 ; j<d->size ; j++) {
if (d->key[j]==NULL)
continue ;
if (!strncmp(d->key[j], keym, seclen+1)) {
fprintf(f,
"%-30s = %s\n",
d->key[j]+seclen+1,
d->val[j] ? d->val[j] : "");
}
}
}
fprintf(f, "\n");
return ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key
@param d Dictionary to search
@param key Key string to look for
@param def Default value to return if key not found.
@return pointer to statically allocated character string
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the pointer passed as 'def' is returned.
The returned char pointer is pointing to a string allocated in
the dictionary, do not free or modify it.
*/
/*--------------------------------------------------------------------------*/
char * iniparser_getstring(dictionary * d, char * key, char * def)
{
char * lc_key ;
char * sval ;
if (d==NULL || key==NULL)
return def ;
lc_key = strlwc(key);
sval = dictionary_get(d, lc_key, def);
return sval ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
"42" -> 42
"042" -> 34 (octal -> decimal)
"0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
int iniparser_getint(dictionary * d, char * key, int notfound)
{
char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==INI_INVALID_KEY) return notfound ;
return (int)strtol(str, NULL, 0);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a double
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return double
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
*/
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(dictionary * d, char * key, double notfound)
{
char * str ;
str = iniparser_getstring(d, key, INI_INVALID_KEY);
if (str==INI_INVALID_KEY) return notfound ;
return atof(str);
}
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a boolean
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
A true boolean is found if one of the following is matched:
- A string starting with 'y'
- A string starting with 'Y'
- A string starting with 't'
- A string starting with 'T'
- A string starting with '1'
A false boolean is found if one of the following is matched:
- A string starting with 'n'
- A string starting with 'N'
- A string starting with 'f'
- A string starting with 'F'
- A string starting with '0'
The notfound value returned if no boolean is identified, does not
necessarily have to be 0 or 1.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(dictionary * d, char * key, int notfound)
{
char * c ;
int ret ;
c = iniparser_getstring(d, key, INI_INVALID_KEY);
if (c==INI_INVALID_KEY) return notfound ;
if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') {
ret = 1 ;
} else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') {
ret = 0 ;
} else {
ret = notfound ;
}
return ret;
}
/*-------------------------------------------------------------------------*/
/**
@brief Finds out if a given entry exists in a dictionary
@param ini Dictionary to search
@param entry Name of the entry to look for
@return integer 1 if entry exists, 0 otherwise
Finds out if a given entry exists in the dictionary. Since sections
are stored as keys with NULL associated values, this is the only way
of querying for the presence of sections in a dictionary.
*/
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(
dictionary * ini,
char * entry
)
{
int found=0 ;
if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) {
found = 1 ;
}
return found ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Set an entry in a dictionary.
@param ini Dictionary to modify.
@param entry Entry to modify (entry name)
@param val New value to associate to the entry.
@return int 0 if Ok, -1 otherwise.
If the given entry can be found in the dictionary, it is modified to
contain the provided value. If it cannot be found, -1 is returned.
It is Ok to set val to NULL.
*/
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, char * entry, char * val)
{
return dictionary_set(ini, strlwc(entry), val) ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Delete an entry in a dictionary
@param ini Dictionary to modify
@param entry Entry to delete (entry name)
@return void
If the given entry can be found, it is deleted from the dictionary.
*/
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, char * entry)
{
dictionary_unset(ini, strlwc(entry));
}
/*-------------------------------------------------------------------------*/
/**
@brief Load a single line from an INI file
@param input_line Input line, may be concatenated multi-line input
@param section Output space to store section
@param key Output space to store key
@param value Output space to store value
@return line_status value
*/
/*--------------------------------------------------------------------------*/
static line_status iniparser_line(
char * input_line,
char * section,
char * key,
char * value)
{
line_status sta ;
char line[ASCIILINESZ+1];
int len ;
strcpy(line, strstrip(input_line));
len = (int)strlen(line);
sta = LINE_UNPROCESSED ;
if (len<1) {
/* Empty line */
sta = LINE_EMPTY ;
} else if (line[0]=='#' || line[0]==';') {
/* Comment line */
sta = LINE_COMMENT ;
} else if (line[0]=='[' && line[len-1]==']') {
/* Section name */
sscanf(line, "[%[^]]", section);
strcpy(section, strstrip(section));
strcpy(section, strlwc(section));
sta = LINE_SECTION ;
} else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2
|| sscanf (line, "%[^=] = '%[^\']'", key, value) == 2
|| sscanf (line, "%[^=] = %[^;#]", key, value) == 2) {
/* Usual key=value, with or without comments */
strcpy(key, strstrip(key));
strcpy(key, strlwc(key));
strcpy(value, strstrip(value));
/*
* sscanf cannot handle '' or "" as empty values
* this is done here
*/
if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) {
value[0]=0 ;
}
sta = LINE_VALUE ;
} else if (sscanf(line, "%[^=] = %[;#]", key, value)==2
|| sscanf(line, "%[^=] %[=]", key, value) == 2) {
/*
* Special cases:
* key=
* key=;
* key=#
*/
strcpy(key, strstrip(key));
strcpy(key, strlwc(key));
value[0]=0 ;
sta = LINE_VALUE ;
} else {
/* Generate syntax error */
sta = LINE_ERROR ;
}
return sta ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param ininame Name of the ini file to read.
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the name of the file to be read. It returns a dictionary object that
should not be accessed directly, but through accessor functions
instead.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(char * ininame)
{
FILE * in ;
char line [ASCIILINESZ+1] ;
char section [ASCIILINESZ+1] ;
char key [ASCIILINESZ+1] ;
char tmp [ASCIILINESZ+1] ;
char val [ASCIILINESZ+1] ;
int last=0 ;
int len ;
int lineno=0 ;
int errs=0;
dictionary * dict ;
if ((in=fopen(ininame, "r"))==NULL) {
fprintf(stderr, "iniparser: cannot open %s\n", ininame);
return NULL ;
}
dict = dictionary_new(0) ;
if (!dict) {
fclose(in);
return NULL ;
}
memset(line, 0, ASCIILINESZ);
memset(section, 0, ASCIILINESZ);
memset(key, 0, ASCIILINESZ);
memset(val, 0, ASCIILINESZ);
last=0 ;
while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) {
lineno++ ;
len = (int)strlen(line)-1;
if (len==0)
continue;
/* Safety check against buffer overflows */
if (line[len]!='\n') {
fprintf(stderr,
"iniparser: input line too long in %s (%d)\n",
ininame,
lineno);
dictionary_del(dict);
fclose(in);
return NULL ;
}
/* Get rid of \n and spaces at end of line */
while ((len>=0) &&
((line[len]=='\n') || (isspace(line[len])))) {
line[len]=0 ;
len-- ;
}
/* Detect multi-line */
if (line[len]=='\\') {
/* Multi-line value */
last=len ;
continue ;
} else {
last=0 ;
}
switch (iniparser_line(line, section, key, val)) {
case LINE_EMPTY:
case LINE_COMMENT:
break ;
case LINE_SECTION:
errs = dictionary_set(dict, section, NULL);
break ;
case LINE_VALUE:
sprintf(tmp, "%s:%s", section, key);
errs = dictionary_set(dict, tmp, val) ;
break ;
case LINE_ERROR:
fprintf(stderr, "iniparser: syntax error in %s (%d):\n",
ininame,
lineno);
fprintf(stderr, "-> %s\n", line);
errs++ ;
break;
default:
break ;
}
memset(line, 0, ASCIILINESZ);
last=0;
if (errs<0) {
fprintf(stderr, "iniparser: memory allocation failure\n");
break ;
}
}
if (errs) {
dictionary_del(dict);
dict = NULL ;
}
fclose(in);
return dict ;
}
/*-------------------------------------------------------------------------*/
/**
@brief Free all memory associated to an ini dictionary
@param d Dictionary to free
@return void
Free all memory associated to an ini dictionary.
It is mandatory to call this function before the dictionary object
gets out of the current context.
*/
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d)
{
dictionary_del(d);
}
/* vim: set ts=4 et sw=4 tw=75 */

Просмотреть файл

@ -0,0 +1,273 @@
/*-------------------------------------------------------------------------*/
/**
@file iniparser.h
@author N. Devillard
@date Sep 2007
@version 3.0
@brief Parser for ini files.
*/
/*--------------------------------------------------------------------------*/
/*
$Id: iniparser.h,v 1.26 2011-03-02 20:15:13 ndevilla Exp $
$Revision: 1.26 $
*/
#ifndef _INIPARSER_H_
#define _INIPARSER_H_
/*---------------------------------------------------------------------------
Includes
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* The following #include is necessary on many Unixes but not Linux.
* It is not needed for Windows platforms.
* Uncomment it if needed.
*/
/* #include <unistd.h> */
#include "dictionary.h"
/*-------------------------------------------------------------------------*/
/**
@brief Get number of sections in a dictionary
@param d Dictionary to examine
@return int Number of sections found in dictionary
This function returns the number of sections found in a dictionary.
The test to recognize sections is done on the string stored in the
dictionary: a section name is given as "section" whereas a key is
stored as "section:key", thus the test looks for entries that do not
contain a colon.
This clearly fails in the case a section name contains a colon, but
this should simply be avoided.
This function returns -1 in case of error.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getnsec(dictionary * d);
/*-------------------------------------------------------------------------*/
/**
@brief Get name for section n in a dictionary.
@param d Dictionary to examine
@param n Section number (from 0 to nsec-1).
@return Pointer to char string
This function locates the n-th section in a dictionary and returns
its name as a pointer to a string statically allocated inside the
dictionary. Do not free or modify the returned string!
This function returns NULL in case of error.
*/
/*--------------------------------------------------------------------------*/
char * iniparser_getsecname(dictionary * d, int n);
/*-------------------------------------------------------------------------*/
/**
@brief Save a dictionary to a loadable ini file
@param d Dictionary to dump
@param f Opened file pointer to dump to
@return void
This function dumps a given dictionary into a loadable ini file.
It is Ok to specify @c stderr or @c stdout as output files.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump_ini(dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
@brief Dump a dictionary to an opened file pointer.
@param d Dictionary to dump.
@param f Opened file pointer to dump to.
@return void
This function prints out the contents of a dictionary, one element by
line, onto the provided file pointer. It is OK to specify @c stderr
or @c stdout as output files. This function is meant for debugging
purposes mostly.
*/
/*--------------------------------------------------------------------------*/
void iniparser_dump(dictionary * d, FILE * f);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key
@param d Dictionary to search
@param key Key string to look for
@param def Default value to return if key not found.
@return pointer to statically allocated character string
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the pointer passed as 'def' is returned.
The returned char pointer is pointing to a string allocated in
the dictionary, do not free or modify it.
*/
/*--------------------------------------------------------------------------*/
char * iniparser_getstring(dictionary * d, char * key, char * def);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to an int
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
Supported values for integers include the usual C notation
so decimal, octal (starting with 0) and hexadecimal (starting with 0x)
are supported. Examples:
- "42" -> 42
- "042" -> 34 (octal -> decimal)
- "0x42" -> 66 (hexa -> decimal)
Warning: the conversion may overflow in various ways. Conversion is
totally outsourced to strtol(), see the associated man page for overflow
handling.
Credits: Thanks to A. Becker for suggesting strtol()
*/
/*--------------------------------------------------------------------------*/
int iniparser_getint(dictionary * d, char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a double
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return double
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
*/
/*--------------------------------------------------------------------------*/
double iniparser_getdouble(dictionary * d, char * key, double notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Get the string associated to a key, convert to a boolean
@param d Dictionary to search
@param key Key string to look for
@param notfound Value to return in case of error
@return integer
This function queries a dictionary for a key. A key as read from an
ini file is given as "section:key". If the key cannot be found,
the notfound value is returned.
A true boolean is found if one of the following is matched:
- A string starting with 'y'
- A string starting with 'Y'
- A string starting with 't'
- A string starting with 'T'
- A string starting with '1'
A false boolean is found if one of the following is matched:
- A string starting with 'n'
- A string starting with 'N'
- A string starting with 'f'
- A string starting with 'F'
- A string starting with '0'
The notfound value returned if no boolean is identified, does not
necessarily have to be 0 or 1.
*/
/*--------------------------------------------------------------------------*/
int iniparser_getboolean(dictionary * d, char * key, int notfound);
/*-------------------------------------------------------------------------*/
/**
@brief Set an entry in a dictionary.
@param ini Dictionary to modify.
@param entry Entry to modify (entry name)
@param val New value to associate to the entry.
@return int 0 if Ok, -1 otherwise.
If the given entry can be found in the dictionary, it is modified to
contain the provided value. If it cannot be found, -1 is returned.
It is Ok to set val to NULL.
*/
/*--------------------------------------------------------------------------*/
int iniparser_set(dictionary * ini, char * entry, char * val);
/*-------------------------------------------------------------------------*/
/**
@brief Delete an entry in a dictionary
@param ini Dictionary to modify
@param entry Entry to delete (entry name)
@return void
If the given entry can be found, it is deleted from the dictionary.
*/
/*--------------------------------------------------------------------------*/
void iniparser_unset(dictionary * ini, char * entry);
/*-------------------------------------------------------------------------*/
/**
@brief Finds out if a given entry exists in a dictionary
@param ini Dictionary to search
@param entry Name of the entry to look for
@return integer 1 if entry exists, 0 otherwise
Finds out if a given entry exists in the dictionary. Since sections
are stored as keys with NULL associated values, this is the only way
of querying for the presence of sections in a dictionary.
*/
/*--------------------------------------------------------------------------*/
int iniparser_find_entry(dictionary * ini, char * entry) ;
/*-------------------------------------------------------------------------*/
/**
@brief Parse an ini file and return an allocated dictionary object
@param ininame Name of the ini file to read.
@return Pointer to newly allocated dictionary
This is the parser for ini files. This function is called, providing
the name of the file to be read. It returns a dictionary object that
should not be accessed directly, but through accessor functions
instead.
The returned dictionary must be freed using iniparser_freedict().
*/
/*--------------------------------------------------------------------------*/
dictionary * iniparser_load(char * ininame);
/*-------------------------------------------------------------------------*/
/**
@brief Free all memory associated to an ini dictionary
@param d Dictionary to free
@return void
Free all memory associated to an ini dictionary.
It is mandatory to call this function before the dictionary object
gets out of the current context.
*/
/*--------------------------------------------------------------------------*/
void iniparser_freedict(dictionary * d);
#endif

Просмотреть файл

@ -0,0 +1,2 @@
[mozprocess1.py]
[mozprocess2.py]

Просмотреть файл

@ -0,0 +1,187 @@
#!/usr/bin/env python
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# 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.org code.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
import os
import subprocess
import sys
import unittest
from time import sleep
from mozprocess import processhandler
here = os.path.dirname(os.path.abspath(__file__))
def make_proclaunch(aDir):
"""
Makes the proclaunch executable.
Params:
aDir - the directory in which to issue the make commands
Returns:
the path to the proclaunch executable that is generated
"""
p = subprocess.call(["make"], cwd=aDir)
if sys.platform == "win32":
exepath = os.path.join(aDir, "proclaunch.exe")
else:
exepath = os.path.join(aDir, "proclaunch")
return exepath
def check_for_process(processName):
"""
Use to determine if process of the given name is still running.
Returns:
detected -- True if process is detected to exist, False otherwise
output -- if process exists, stdout of the process, '' otherwise
"""
output = ''
if sys.platform == "win32":
# On windows we use tasklist
p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE)
output = p1.communicate()[0]
detected = False
for line in output:
if processName in line:
detected = True
break
else:
p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
output = p2.communicate()[0]
detected = False
for line in output:
if "grep %s" % processName in line:
continue
elif processName in line:
detected = True
break
return detected, output
class ProcTest1(unittest.TestCase):
def __init__(self, *args, **kwargs):
# Ideally, I'd use setUpClass but that only exists in 2.7.
# So, we'll do this make step now.
self.proclaunch = make_proclaunch(here)
unittest.TestCase.__init__(self, *args, **kwargs)
def test_process_normal_finish(self):
"""Process is started, runs to completion while we wait for it"""
p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
cwd=here)
p.run()
p.waitForFinish()
detected, output = check_for_process(self.proclaunch)
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
def test_process_waittimeout(self):
""" Process is started, runs but we time out waiting on it
to complete
"""
p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout.ini"],
cwd=here)
p.run()
p.waitForFinish(timeout=10)
detected, output = check_for_process(self.proclaunch)
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout,
False,
['returncode', 'didtimeout'])
def test_process_kill(self):
""" Process is started, we kill it
"""
p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
cwd=here)
p.run()
p.kill()
detected, output = check_for_process(self.proclaunch)
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
def determine_status(self,
detected=False,
output='',
returncode=0,
didtimeout=False,
isalive=False,
expectedfail=[]):
"""
Use to determine if the situation has failed.
Parameters:
detected -- value from check_for_process to determine if the process is detected
output -- string of data from detected process, can be ''
returncode -- return code from process, defaults to 0
didtimeout -- True if process timed out, defaults to False
isalive -- Use True to indicate we pass if the process exists; however, by default
the test will pass if the process does not exist (isalive == False)
expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail
"""
if 'returncode' in expectedfail:
self.assertTrue(returncode, "Detected an expected non-zero return code")
else:
self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode)
if 'didtimeout' in expectedfail:
self.assertTrue(didtimeout, "Process timed out as expected")
else:
self.assertTrue(not didtimeout, "Detected that process timed out")
if detected:
self.assertTrue(isalive, "Detected process is still running, process output: %s" % output)
else:
self.assertTrue(not isalive, "Process ended")
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -0,0 +1,177 @@
#!/usr/bin/env python
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# 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.org code.
#
# The Initial Developer of the Original Code is
# the Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
import os
import subprocess
import sys
import unittest
from time import sleep
from mozprocess import processhandler
here = os.path.dirname(os.path.abspath(__file__))
# This tests specifically the case reported in bug 671316
# TODO: Because of the way mutt works we can't just load a utils.py in here.
# so, for all process handler tests, copy these two
# utility functions to to the top of your source.
def make_proclaunch(aDir):
"""
Makes the proclaunch executable.
Params:
aDir - the directory in which to issue the make commands
Returns:
the path to the proclaunch executable that is generated
"""
p = subprocess.call(["make"], cwd=aDir)
if sys.platform == "win32":
exepath = os.path.join(aDir, "proclaunch.exe")
else:
exepath = os.path.join(aDir, "proclaunch")
return exepath
def check_for_process(processName):
"""
Use to determine if process is still running.
Returns:
detected -- True if process is detected to exist, False otherwise
output -- if process exists, stdout of the process, '' otherwise
"""
output = ''
if sys.platform == "win32":
# On windows we use tasklist
p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE)
output = p1.communicate()[0]
detected = False
for line in output:
if processName in line:
detected = True
break
else:
p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
output = p2.communicate()[0]
detected = False
for line in output:
if "grep %s" % processName in line:
continue
elif processName in line:
detected = True
break
return detected, output
class ProcTest2(unittest.TestCase):
def __init__(self, *args, **kwargs):
# Ideally, I'd use setUpClass but that only exists in 2.7.
# So, we'll do this make step now.
self.proclaunch = make_proclaunch(here)
unittest.TestCase.__init__(self, *args, **kwargs)
def test_process_waittimeout(self):
""" Process is started, runs to completion before our wait times out
"""
p = processhandler.ProcessHandler([self.proclaunch,
"process_waittimeout_10s.ini"],
cwd=here)
p.run()
p.waitForFinish(timeout=30)
detected, output = check_for_process(self.proclaunch)
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
def test_process_waitnotimeout(self):
""" Process is started runs to completion while we wait indefinitely
"""
p = processhandler.ProcessHandler([self.proclaunch,
"process_waittimeout_10s.ini"],
cwd=here)
p.run()
p.waitForFinish()
detected, output = check_for_process(self.proclaunch)
self.determine_status(detected,
output,
p.proc.returncode,
p.didTimeout)
def determine_status(self,
detected=False,
output = '',
returncode = 0,
didtimeout = False,
isalive=False,
expectedfail=[]):
"""
Use to determine if the situation has failed.
Parameters:
detected -- value from check_for_process to determine if the process is detected
output -- string of data from detected process, can be ''
returncode -- return code from process, defaults to 0
didtimeout -- True if process timed out, defaults to False
isalive -- Use True to indicate we pass if the process exists; however, by default
the test will pass if the process does not exist (isalive == False)
expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail
"""
if 'returncode' in expectedfail:
self.assertTrue(returncode, "Detected an expected non-zero return code")
else:
self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode)
if 'didtimeout' in expectedfail:
self.assertTrue(didtimeout, "Process timed out as expected")
else:
self.assertTrue(not didtimeout, "Detected that process timed out")
if detected:
self.assertTrue(isalive, "Detected process is still running, process output: %s" % output)
else:
self.assertTrue(not isalive, "Process ended")
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -0,0 +1,11 @@
[main]
children=c1,c2
maxtime=60
[c1]
children=2
maxtime=60
[c2]
children=0
maxtime=30

Просмотреть файл

@ -0,0 +1,11 @@
[main]
children=c1,c2
maxtime=300
[c1]
children=2
maxtime=300
[c2]
children=3
maxtime=300

Просмотреть файл

@ -0,0 +1,8 @@
[main]
children=c1
maxtime=10
[c1]
children=2
maxtime=5

Просмотреть файл

@ -0,0 +1,189 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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.org code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Clint Talbert <ctalbert@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdio.h>
#include <stdlib.h>
#include "iniparser.h"
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
extern int iniparser_getint(dictionary *d, char *key, int notfound);
extern char *iniparser_getstring(dictionary *d, char *key, char *def);
// This is the windows launcher function
int launchWindows(int children, int maxtime) {
_TCHAR cmdline[50];
STARTUPINFO startup;
PROCESS_INFORMATION procinfo;
BOOL rv = 0;
_stprintf(cmdline, _T("proclaunch.exe %d %d"), children, maxtime);
ZeroMemory(&startup, sizeof(STARTUPINFO));
startup.cb = sizeof(STARTUPINFO);
ZeroMemory(&procinfo, sizeof(PROCESS_INFORMATION));
printf("Launching process!\n");
rv = CreateProcess(NULL,
cmdline,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&startup,
&procinfo);
if (!rv) {
DWORD dw = GetLastError();
printf("error: %d\n", dw);
}
CloseHandle(procinfo.hProcess);
CloseHandle(procinfo.hThread);
return 0;
}
#endif
int main(int argc, char **argv) {
int children = 0;
int maxtime = 0;
int passedtime = 0;
dictionary *dict = NULL;
// Command line handling
if (argc == 1 || (0 == strcmp(argv[1], "-h")) || (0 == strcmp(argv[1], "--help"))) {
printf("ProcLauncher takes an ini file. Specify the ini file as the only\n");
printf("parameter of the command line:\n");
printf("proclauncher my.ini\n\n");
printf("The ini file has the form:\n");
printf("[main]\n");
printf("children=child1,child2 ; These comma separated values are sections\n");
printf("maxtime=60 ; Max time this process lives\n");
printf("[child1] ; Here is a child section\n");
printf("children=3 ; You can have grandchildren: this spawns 3 of them for child1\n");
printf("maxtime=30 ; Max time, note it's in seconds. If this time\n");
printf(" ; is > main:maxtime then the child process will be\n");
printf(" ; killed when the parent exits. Also, grandchildren\n");
printf("[child2] ; inherit this maxtime and can't change it.\n");
printf("maxtime=25 ; You can call these sections whatever you want\n");
printf("children=0 ; as long as you reference them in a children attribute\n");
printf("....\n");
return 0;
} else if (argc == 2) {
// This is ini file mode:
// proclauncher <inifile>
dict = iniparser_load(argv[1]);
} else if (argc == 3) {
// Then we've been called in child process launching mode:
// proclauncher <children> <maxtime>
children = atoi(argv[1]);
maxtime = atoi(argv[2]);
}
if (dict) {
/* Dict operation */
char *childlist = iniparser_getstring(dict, "main:children", NULL);
maxtime = iniparser_getint(dict, (char*)"main:maxtime", 10);;
if (childlist) {
int c = 0, m = 10;
char childkey[50], maxkey[50];
char cmd[25];
char *token = strtok(childlist, ",");
while (token) {
// Reset defaults
memset(childkey, 0, 50);
memset(maxkey, 0, 50);
memset(cmd, 0, 25);
c = 0;
m = 10;
sprintf(childkey, "%s:children", token);
sprintf(maxkey, "%s:maxtime", token);
c = iniparser_getint(dict, childkey, 0);
m = iniparser_getint(dict, maxkey, 10);
// Launch the child process
#ifdef _WIN32
launchWindows(c, m);
#else
sprintf(cmd, "./proclaunch %d %d &", c, m);
system(cmd);
#endif
// Get the next child entry
token = strtok(NULL, ",");
}
}
iniparser_freedict(dict);
} else {
// Child Process operation - put on your recursive thinking cap
char cmd[25];
// This is launching grandchildren, there are no great grandchildren, so we
// pass in a 0 for the children to spawn.
#ifdef _WIN32
while(children > 0) {
launchWindows(0, maxtime);
children--;
}
#else
sprintf(cmd, "./proclaunch %d %d &", 0, maxtime);
printf("Launching child process: %s\n", cmd);
while (children > 0) {
system(cmd);
children--;
}
#endif
}
/* Now we have launched all the children. Let's wait for max time before returning
This does pseudo busy waiting just to appear active */
while (passedtime < maxtime) {
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif
passedtime++;
}
exit(0);
return 0;
}

Просмотреть файл

@ -2,7 +2,8 @@
is a python tool for creating and managing profiles for Mozilla's
applications (Firefox, Thunderbird, etc.). In addition to creating profiles,
mozprofile can install [addons](https://developer.mozilla.org/en/addons)
and set [preferences](https://developer.mozilla.org/En/A_Brief_Guide_to_Mozilla_Preferences).
and set
[preferences](https://developer.mozilla.org/En/A_Brief_Guide_to_Mozilla_Preferences).
Mozprofile can be utilized from the command line or as an API.
@ -15,7 +16,7 @@ The profile to be operated on may be specified with the `--profile`
switch. If a profile is not specified, one will be created in a
temporary directory which will be echoed to the terminal:
(mozmill)> mozprofile
(mozmill)> mozprofile
/tmp/tmp4q1iEU.mozrunner
(mozmill)> ls /tmp/tmp4q1iEU.mozrunner
user.js
@ -29,12 +30,72 @@ To run mozprofile from the command line enter:
To use mozprofile as an API you can import
[mozprofile.profile](https://github.com/mozilla/mozbase/tree/master/mozprofile/mozprofile/profile.py)
and/or the
[AddonManager](https://github.com/mozilla/mozbase/tree/master/mozprofile/mozprofile/addons.py).
[AddonManager](https://github.com/mozilla/mozbase/tree/master/mozprofile/mozprofile/addons.py).
`mozprofile.profile` features a generic `Profile` class. In addition,
subclasses `FirefoxProfile` and `ThundebirdProfile` are available
with preset preferences for those applications.
`mozprofile.profile:Profile`:
def __init__(self,
profile=None, # Path to the profile
addons=None, # String of one or list of addons to install
addon_manifests=None, # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
preferences=None, # Dictionary or class of preferences
locations=None, # locations to proxy
proxy=False, # setup a proxy
restore=True # If true remove all installed addons preferences when cleaning up
):
def reset(self):
"""reset the profile to the beginning state"""
def set_preferences(self, preferences, filename='user.js'):
"""Adds preferences dict to profile preferences"""
def clean_preferences(self):
"""Removed preferences added by mozrunner."""
def cleanup(self):
"""Cleanup operations for the profile."""
`mozprofile.addons:AddonManager`:
def __init__(self, profile):
"""profile - the path to the profile for which we install addons"""
def install_addons(self, addons=None, manifests=None):
"""
Installs all types of addons
addons - a list of addon paths to install
manifest - a list of addon manifests to install
"""
@classmethod
def get_amo_install_path(self, query):
"""
Return the addon xpi install path for the specified AMO query.
See: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
for query documentation.
"""
@classmethod
def addon_details(cls, addon_path):
"""
returns a dictionary of details about the addon
- addon_path : path to the addon directory
Returns:
{'id': u'rainbow@colors.org', # id of the addon
'version': u'1.4', # version of the addon
'name': u'Rainbow', # name of the addon
'unpack': False } # whether to unpack the addon
"""
def clean_addons(self):
"""Cleans up addons in the profile."""
# Installing Addons

Просмотреть файл

@ -135,7 +135,7 @@ class AddonManager(object):
{'id': u'rainbow@colors.org', # id of the addon
'version': u'1.4', # version of the addon
'name': u'Rainbow', # name of the addon
'unpack': # whether to unpack the addon
'unpack': False } # whether to unpack the addon
"""
# TODO: We don't use the unpack variable yet, but we should: bug 662683

Просмотреть файл

@ -56,7 +56,15 @@ class Profile(object):
"""Handles all operations regarding profile. Created new profiles, installs extensions,
sets preferences and handles cleanup."""
def __init__(self, profile=None, addons=None, addon_manifests=None, preferences=None, locations=None, proxy=False, restore=True):
def __init__(self,
profile=None, # Path to the profile
addons=None, # String of one or list of addons to install
addon_manifests=None, # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
preferences=None, # Dictionary or class of preferences
locations=None, # locations to proxy
proxy=False, # setup a proxy
restore=True # If true remove all installed addons preferences when cleaning up
):
# if true, remove installed addons/prefs afterwards
self.restore = restore
@ -221,7 +229,7 @@ class Profile(object):
def cleanup(self):
"""Cleanup operations on the profile."""
"""Cleanup operations for the profile."""
if self.restore:
if self.create_new:
if os.path.exists(self.profile):

Просмотреть файл

@ -0,0 +1,146 @@
#!/usr/bin/env python
import os
import tempfile
import unittest
import shutil
from mozprofile import addons
class AddonIDTest(unittest.TestCase):
""" Test finding the addon id in a variety of install.rdf styles """
def make_install_rdf(self, filecontents):
path = tempfile.mkdtemp()
f = open(os.path.join(path, "install.rdf"), "w")
f.write(filecontents)
f.close()
return path
def test_addonID(self):
testlist = self.get_test_list()
for t in testlist:
try:
p = self.make_install_rdf(t)
a = addons.AddonManager(os.path.join(p, "profile"))
addon_id = a.addon_details(p)['id']
self.assertTrue(addon_id == "winning", "We got the addon id")
finally:
shutil.rmtree(p)
def get_test_list(self):
""" This just returns a hardcoded list of install.rdf snippets for testing.
When adding snippets for testing, remember that the id we're looking for
is "winning" (no quotes). So, make sure you have that id in your snippet
if you want it to pass.
"""
tests = [
"""<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>winning</em:id>
<em:name>MozMill</em:name>
<em:version>2.0a</em:version>
<em:creator>Adam Christian</em:creator>
<em:description>A testing extension based on the Windmill Testing Framework client source</em:description>
<em:unpack>true</em:unpack>
<em:targetApplication>
<!-- Firefox -->
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.5</em:minVersion>
<em:maxVersion>8.*</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<!-- Thunderbird -->
<Description>
<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
<em:minVersion>3.0a1pre</em:minVersion>
<em:maxVersion>3.2*</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<!-- Sunbird -->
<Description>
<em:id>{718e30fb-e89b-41dd-9da7-e25a45638b28}</em:id>
<em:minVersion>0.6a1</em:minVersion>
<em:maxVersion>1.0pre</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<!-- SeaMonkey -->
<Description>
<em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
<em:minVersion>2.0a1</em:minVersion>
<em:maxVersion>2.1*</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<!-- Songbird -->
<Description>
<em:id>songbird@songbirdnest.com</em:id>
<em:minVersion>0.3pre</em:minVersion>
<em:maxVersion>1.3.0a</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>1.9.1</em:minVersion>
<em:maxVersion>2.0*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>""",
"""<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:targetApplication>
<!-- Firefox -->
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.5</em:minVersion>
<em:maxVersion>8.*</em:maxVersion>
</Description>
</em:targetApplication>
<em:id>winning</em:id>
<em:name>MozMill</em:name>
<em:version>2.0a</em:version>
<em:creator>Adam Christian</em:creator>
<em:description>A testing extension based on the Windmill Testing Framework client source</em:description>
<em:unpack>true</em:unpack>
</Description>
</RDF>""",
"""<RDF xmlns="http://www.mozilla.org/2004/em-rdf#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description about="urn:mozilla:install-manifest">
<id>winning</id>
<name>foo</name>
<version>42</version>
<description>A testing extension based on the Windmill Testing Framework client source</description>
</rdf:Description>
</RDF>""",
"""<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:foobar="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<foobar:targetApplication>
<!-- Firefox -->
<Description>
<foobar:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</foobar:id>
<foobar:minVersion>3.5</foobar:minVersion>
<foobar:maxVersion>8.*</foobar:maxVersion>
</Description>
</foobar:targetApplication>
<foobar:id>winning</foobar:id>
<foobar:name>MozMill</foobar:name>
<foobar:version>2.0a</foobar:version>
<foobar:creator>Adam Christian</foobar:creator>
<foobar:description>A testing extension based on the Windmill Testing Framework client source</foobar:description>
<foobar:unpack>true</foobar:unpack>
</Description>
</RDF>"""]
return tests
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -0,0 +1,3 @@
[addonid.py]
[server_locations.py]
[testprofile.py]

Просмотреть файл

@ -0,0 +1,65 @@
#!/usr/bin/env python
import os
import shutil
import tempfile
import unittest
from mozprofile.permissions import PermissionsManager
class ServerLocationsTest(unittest.TestCase):
"""test server locations"""
locations = """
# This is the primary location from which tests run.
#
http://mochi.test:8888 primary,privileged
# a few test locations
http://127.0.0.1:80 privileged
http://127.0.0.1:8888 privileged
https://test:80 privileged
http://mochi.test:8888 privileged
http://example.org:80 privileged
http://test1.example.org:80 privileged
"""
def compare_location(self, location, scheme, host, port, options):
self.assertEqual(location.scheme, scheme)
self.assertEqual(location.host, host)
self.assertEqual(location.port, port)
self.assertEqual(location.options, options)
def test_server_locations(self):
# make a permissions manager
# needs a pointless temporary directory for now
tempdir = tempfile.mkdtemp()
permissions = PermissionsManager(tempdir)
# write a permissions file
fd, filename = tempfile.mkstemp()
os.write(fd, self.locations)
os.close(fd)
# read the locations
locations = permissions.read_locations(filename)
# ensure that they're what we expect
self.assertEqual(len(locations), 7)
self.compare_location(locations[0], 'http', 'mochi.test', '8888', ['primary', 'privileged'])
self.compare_location(locations[1], 'http', '127.0.0.1', '80', ['privileged'])
self.compare_location(locations[2], 'http', '127.0.0.1', '8888', ['privileged'])
self.compare_location(locations[3], 'https', 'test', '80', ['privileged'])
self.compare_location(locations[4], 'http', 'mochi.test', '8888', ['privileged'])
self.compare_location(locations[5], 'http', 'example.org', '80', ['privileged'])
self.compare_location(locations[6], 'http', 'test1.example.org', '80', ['privileged'])
# cleanup
del permissions
shutil.rmtree(tempdir)
os.remove(filename)
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -0,0 +1,141 @@
#!/usr/bin/env python
import os
import shutil
import subprocess
import tempfile
import unittest
from mozprofile.prefs import Preferences
from mozprofile.profile import Profile
class ProfileTest(unittest.TestCase):
"""test mozprofile"""
def run_command(self, *args):
"""
runs mozprofile;
returns (stdout, stderr, code)
"""
process = subprocess.Popen(args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
stdout = stdout.strip()
stderr = stderr.strip()
return stdout, stderr, process.returncode
def compare_generated(self, _prefs, commandline):
"""
writes out to a new profile with mozprofile command line
reads the generated preferences with prefs.py
compares the results
cleans up
"""
profile, stderr, code = self.run_command(*commandline)
prefs_file = os.path.join(profile, 'user.js')
self.assertTrue(os.path.exists(prefs_file))
read = Preferences.read_prefs(prefs_file)
if isinstance(_prefs, dict):
read = dict(read)
self.assertEqual(_prefs, read)
shutil.rmtree(profile)
def test_basic_prefs(self):
_prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"}
commandline = ["mozprofile"]
_prefs = _prefs.items()
for pref, value in _prefs:
commandline += ["--pref", "%s:%s" % (pref, value)]
self.compare_generated(_prefs, commandline)
def test_ordered_prefs(self):
"""ensure the prefs stay in the right order"""
_prefs = [("browser.startup.homepage", "http://planet.mozilla.org/"),
("zoom.minPercent", 30),
("zoom.maxPercent", 300),
("webgl.verbose", 'false')]
commandline = ["mozprofile"]
for pref, value in _prefs:
commandline += ["--pref", "%s:%s" % (pref, value)]
_prefs = [(i, Preferences.cast(j)) for i, j in _prefs]
self.compare_generated(_prefs, commandline)
def test_ini(self):
# write the .ini file
_ini = """[DEFAULT]
browser.startup.homepage = http://planet.mozilla.org/
[foo]
browser.startup.homepage = http://github.com/
"""
fd, name = tempfile.mkstemp(suffix='.ini')
os.write(fd, _ini)
os.close(fd)
commandline = ["mozprofile", "--preferences", name]
# test the [DEFAULT] section
_prefs = {'browser.startup.homepage': 'http://planet.mozilla.org/'}
self.compare_generated(_prefs, commandline)
# test a specific section
_prefs = {'browser.startup.homepage': 'http://github.com/'}
commandline[-1] = commandline[-1] + ':foo'
self.compare_generated(_prefs, commandline)
# cleanup
os.remove(name)
def test_magic_markers(self):
"""ensure our magic markers are working"""
profile = Profile()
prefs_file = os.path.join(profile.profile, 'user.js')
# we shouldn't have any initial preferences
initial_prefs = Preferences.read_prefs(prefs_file)
self.assertFalse(initial_prefs)
initial_prefs = file(prefs_file).read().strip()
self.assertFalse(initial_prefs)
# add some preferences
prefs1 = [("browser.startup.homepage", "http://planet.mozilla.org/"),
("zoom.minPercent", 30)]
profile.set_preferences(prefs1)
self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
lines = file(prefs_file).read().strip().splitlines()
self.assertTrue('#MozRunner Prefs Start' in lines)
self.assertTrue('#MozRunner Prefs End' in lines)
# add some more preferences
prefs2 = [("zoom.maxPercent", 300),
("webgl.verbose", 'false')]
profile.set_preferences(prefs2)
self.assertEqual(prefs1 + prefs2, Preferences.read_prefs(prefs_file))
lines = file(prefs_file).read().strip().splitlines()
self.assertTrue(lines.count('#MozRunner Prefs Start') == 2)
self.assertTrue(lines.count('#MozRunner Prefs End') == 2)
# now clean it up
profile.clean_preferences()
final_prefs = Preferences.read_prefs(prefs_file)
self.assertFalse(final_prefs)
lines = file(prefs_file).read().strip().splitlines()
self.assertTrue('#MozRunner Prefs Start' not in lines)
self.assertTrue('#MozRunner Prefs End' not in lines)
def test_json(self):
_prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"}
json = '{"browser.startup.homepage": "http://planet.mozilla.org/"}'
# just repr it...could use the json module but we don't need it here
fd, name = tempfile.mkstemp(suffix='.json')
os.write(fd, json)
os.close(fd)
commandline = ["mozprofile", "--preferences", name]
self.compare_generated(_prefs, commandline)
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -44,6 +44,7 @@ __all__ = ['Runner', 'ThunderbirdRunner', 'FirefoxRunner', 'runners', 'CLI', 'cl
import mozinfo
import optparse
import os
import platform
import sys
import ConfigParser
@ -54,37 +55,29 @@ from mozprocess.processhandler import ProcessHandler
package_metadata = get_metadata_from_egg('mozrunner')
class BinaryLocationException(Exception):
"""exception for failure to find the binary"""
class Runner(object):
"""Handles all running operations. Finds bins, runs and kills the process."""
### data to be filled in by subclasses
profile = Profile # profile class to use by default
names = [] # names of application to look for on PATH
app_name = '' # name of application in windows registry
program_names = [] # names of application in windows program files
profile_class = Profile # profile class to use by default
@classmethod
def create(cls, binary=None, cmdargs=None, env=None, kp_kwargs=None, profile_args=None,
def create(cls, binary, cmdargs=None, env=None, kp_kwargs=None, profile_args=None,
clean_profile=True, process_class=ProcessHandler):
profile = cls.profile_class(**(profile_args or {}))
return cls(profile, binary=binary, cmdargs=cmdargs, env=env, kp_kwargs=kp_kwargs,
clean_profile=clean_profile, process_class=process_class)
def __init__(self, profile, binary=None, cmdargs=None, env=None,
def __init__(self, profile, binary, cmdargs=None, env=None,
kp_kwargs=None, clean_profile=True, process_class=ProcessHandler):
self.process_handler = None
self.process_class = process_class
self.profile = profile
self.clean_profile = clean_profile
self.firstrun = False
# find the binary
self.binary = self.__class__.get_binary(binary)
self.binary = binary
if not self.binary:
raise Exception("Binary not specified")
if not os.path.exists(self.binary):
raise OSError("Binary path does not exist: %s" % self.binary)
@ -119,82 +112,6 @@ class Runner(object):
# arguments for ProfessHandler.Process
self.kp_kwargs = kp_kwargs or {}
@classmethod
def get_binary(cls, binary=None):
"""determine the binary"""
if binary is None:
binary = cls.find_binary()
if binary is None:
raise BinaryLocationException("Your binary could not be located; you will need to set it")
return binary
elif mozinfo.isMac and binary.find('Contents/MacOS/') == -1:
return os.path.join(binary, 'Contents/MacOS/%s-bin' % cls.names[0])
else:
return binary
@classmethod
def find_binary(cls):
"""Finds the binary for class names if one was not provided."""
binary = None
if mozinfo.isUnix:
for name in cls.names:
binary = findInPath(name)
if binary:
return binary
elif mozinfo.isWin:
# find the default executable from the windows registry
try:
# assumes cls.app_name is defined, as it should be for implementors
import _winreg
app_key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r"Software\Mozilla\Mozilla %s" % cls.app_name)
version, _type = _winreg.QueryValueEx(app_key, "CurrentVersion")
version_key = _winreg.OpenKey(app_key, version + r"\Main")
path, _ = _winreg.QueryValueEx(version_key, "PathToExe")
return path
except: # XXX not sure what type of exception this should be
pass
# search for the binary in the path
for name in cls.names:
binary = findInPath(name)
if binary:
return binary
# search for the binary in program files
if sys.platform == 'cygwin':
program_files = os.environ['PROGRAMFILES']
else:
program_files = os.environ['ProgramFiles']
program_files = [program_files]
if "ProgramFiles(x86)" in os.environ:
program_files.append(os.environ["ProgramFiles(x86)"])
for program_file in program_files:
for program_name in cls.program_names:
path = os.path.join(program_name, program_file, 'firefox.exe')
if os.path.isfile(path):
return path
elif mozinfo.isMac:
for name in cls.names:
appdir = os.path.join('Applications', name.capitalize()+'.app')
if os.path.isdir(os.path.join(os.path.expanduser('~/'), appdir)):
binary = os.path.join(os.path.expanduser('~/'), appdir,
'Contents/MacOS/'+name+'-bin')
elif os.path.isdir('/'+appdir):
binary = os.path.join("/"+appdir, 'Contents/MacOS/'+name+'-bin')
if binary is not None:
if not os.path.isfile(binary):
binary = binary.replace(name+'-bin', 'firefox-bin')
if not os.path.isfile(binary):
binary = None
if binary:
return binary
return binary
@property
def command(self):
"""Returns the command list to run."""
@ -231,21 +148,10 @@ class Runner(object):
# ensure the profile exists
if not self.profile.exists():
self.profile.reset()
self.firstrun = False
# run once to register any extensions
# see:
# - http://hg.mozilla.org/releases/mozilla-1.9.2/file/915a35e15cde/build/automation.py.in#l702
# - http://mozilla-xp.com/mozilla.dev.apps.firefox/Rules-for-when-firefox-bin-restarts-it-s-process
# This run just calls through processhandler to popen directly as we
# are not particuarly cared in tracking this process
if not self.firstrun:
firstrun = ProcessHandler.Process(self.command+['-silent', '-foreground'], env=self.env, **self.kp_kwargs)
firstrun.wait()
self.firstrun = True
# now run for real, this run uses the managed processhandler
self.process_handler = self.process_class(self.command+self.cmdargs, env=self.env, **self.kp_kwargs)
cmd = self._wrap_command(self.command+self.cmdargs)
# this run uses the managed processhandler
self.process_handler = self.process_class(cmd, env=self.env, **self.kp_kwargs)
self.process_handler.run()
def wait(self, timeout=None, outputTimeout=None):
@ -274,28 +180,32 @@ class Runner(object):
if self.clean_profile:
self.profile.cleanup()
def _wrap_command(self, cmd):
"""
If running on OS X 10.5 or older, wrap |cmd| so that it will
be executed as an i386 binary, in case it's a 32-bit/64-bit universal
binary.
"""
if mozinfo.isMac and hasattr(platform, 'mac_ver') and \
platform.mac_ver()[0][:4] < '10.6':
return ["arch", "-arch", "i386"] + cmd
return cmd
__del__ = cleanup
class FirefoxRunner(Runner):
"""Specialized Runner subclass for running Firefox."""
app_name = 'Firefox'
profile_class = FirefoxProfile
program_names = ['Mozilla Firefox']
# (platform-dependent) names of binary
if mozinfo.isMac:
names = ['firefox', 'minefield', 'shiretoko']
elif mozinfo.isUnix:
names = ['firefox', 'mozilla-firefox', 'iceweasel']
elif mozinfo.isWin:
names =['firefox']
else:
raise AssertionError("I don't know what platform you're on")
def __init__(self, profile, binary=None, **kwargs):
def __init__(self, profile, **kwargs):
Runner.__init__(self, profile, **kwargs)
# take the binary from BROWSER_PATH environment variable
if (not binary) and 'BROWSER_PATH' in os.environ:
binary = os.environ['BROWSER_PATH']
Runner.__init__(self, profile, binary, **kwargs)
# Find application version number
appdir = os.path.dirname(os.path.realpath(self.binary))
@ -311,17 +221,10 @@ class FirefoxRunner(Runner):
'extensions.checkCompatibility.nightly': False}
self.profile.set_preferences(preference)
@classmethod
def get_binary(cls, binary=None):
if (not binary) and 'BROWSER_PATH' in os.environ:
return os.environ['BROWSER_PATH']
return Runner.get_binary(binary)
class ThunderbirdRunner(Runner):
"""Specialized Runner subclass for running Thunderbird"""
app_name = 'Thunderbird'
profile_class = ThunderbirdProfile
names = ["thunderbird", "shredder"]
runners = {'firefox': FirefoxRunner,
'thunderbird': ThunderbirdRunner}

Просмотреть файл

@ -43,7 +43,7 @@ import sys
from setuptools import setup, find_packages
PACKAGE_NAME = "mozrunner"
PACKAGE_VERSION = "4.1"
PACKAGE_VERSION = "5.1"
desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
# take description from README

Просмотреть файл

@ -0,0 +1,5 @@
# mozbase test manifest, in the format of
# https://github.com/mozilla/mozbase/blob/master/manifestdestiny/README.txt
[include:mozprocess/tests/manifest.ini]
[include:mozprofile/tests/manifest.ini]

62
testing/mozbase/test.py Normal file
Просмотреть файл

@ -0,0 +1,62 @@
#!/usr/bin/env python
"""
run mozbase tests
"""
import imp
import manifestparser
import os
import sys
import unittest
here = os.path.dirname(os.path.abspath(__file__))
def unittests(path):
"""return the unittests in a .py file"""
path = os.path.abspath(path)
unittests = []
assert os.path.exists(path)
directory = os.path.dirname(path)
sys.path.insert(0, directory) # insert directory into path for top-level imports
modname = os.path.splitext(os.path.basename(path))[0]
module = imp.load_source(modname, path)
sys.path.pop(0) # remove directory from global path
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(module)
for test in suite:
unittests.append(test)
return unittests
def main(args=sys.argv[1:]):
# read the manifest
if args:
manifests = args
else:
manifests = [os.path.join(here, 'test-manifest.ini')]
missing = []
for manifest in manifests:
# ensure manifests exist
if not os.path.exists(manifest):
missing.append(manifest)
assert not missing, 'manifest%s not found: %s' % ((len(manifests) == 1 and '' or 's'), ', '.join(missing))
manifest = manifestparser.TestManifest(manifests=manifests)
# gather the tests
tests = manifest.active_tests()
unittestlist = []
for test in tests:
unittestlist.extend(unittests(test['path']))
# run the tests
suite = unittest.TestSuite(unittestlist)
runner = unittest.TextTestRunner()
results = runner.run(suite)
# exit according to results
sys.exit((results.failures or results.errors) and 1 or 0)
if __name__ == '__main__':
main()

Просмотреть файл

@ -35,7 +35,7 @@
* ***** END LICENSE BLOCK ***** */
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
/**
* Test for bug 471962 <https://bugzilla.mozilla.org/show_bug.cgi?id=471962>:
@ -100,7 +100,7 @@ function test() {
registerCleanupFunction(function () {
mockTransferRegisterer.unregister();
MockFilePicker.reset();
MockFilePicker.cleanup();
destDir.remove(true);
});

Просмотреть файл

@ -57,7 +57,7 @@ let launcher = {
};
Cu.import("resource://test/MockFilePicker.jsm");
MockFilePicker.reset();
MockFilePicker.init();
MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
function run_test()
@ -143,5 +143,5 @@ function run_test()
prefsService.clearUserPref("browser.privatebrowsing.keep_current_session");
[dir1, dir2, dir3].forEach(function(dir) dir.remove(true));
MockFilePicker.reset();
MockFilePicker.cleanup();
}

Просмотреть файл

@ -5,7 +5,7 @@
// Tests bug 567127 - Add install button to the add-ons manager
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
var gManagerWindow;
var gSawInstallNotification = false;
@ -112,7 +112,7 @@ function test() {
function end_test() {
is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
MockFilePicker.reset();
MockFilePicker.cleanup();
close_manager(gManagerWindow, function() {
finish();
});

Просмотреть файл

@ -11,7 +11,7 @@ var gProvider;
const SETTINGS_ROWS = 8;
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.reset();
MockFilePicker.init();
var observer = {
lastData: null,
@ -91,7 +91,7 @@ function end_test() {
Services.prefs.clearUserPref("extensions.inlinesettings3.radioString");
Services.prefs.clearUserPref("extensions.inlinesettings3.menulist");
MockFilePicker.reset();
MockFilePicker.cleanup();
close_manager(gManagerWindow, function() {
AddonManager.getAddonByID("inlinesettings1@tests.mozilla.org", function(aAddon) {

Просмотреть файл

@ -34,7 +34,6 @@
#include <strings.h> // index
#include <errno.h>
#include <stdarg.h>
#include "v8-support.h"
#include "platform.h"
#include <string.h>

Просмотреть файл

@ -25,7 +25,6 @@
#include <errno.h>
#include "v8-support.h"
#include "platform.h"
// this port is based off of v8 svn revision 9837

Просмотреть файл

@ -3,7 +3,6 @@
// found in the LICENSE file.
#include <windows.h>
#include "v8-support.h"
#include "platform.h"
#include <process.h>

Просмотреть файл

@ -8,6 +8,7 @@
#define __android_log_print(a, ...)
#endif
#include "mozilla/StdInt.h"
#include "mozilla/Util.h"
#include "mozilla/unused.h"
#include "mozilla/TimeStamp.h"
@ -21,17 +22,7 @@
#define LOG(text) printf("Profiler: %s\n", text)
#endif
#ifdef _MSC_VER
typedef __int8 byte;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
typedef uint8 byte;
#endif
typedef byte* Address;
typedef uint8_t* Address;
class MapEntry {
public:

Просмотреть файл

@ -51,11 +51,7 @@
#warning Please add support for your architecture in chromium_types.h
#endif
#ifdef _WIN32
typedef __int32 Atomic32;
#else
typedef int32_t Atomic32;
#endif
typedef int32_t Atomic32;
#if defined(V8_HOST_ARCH_X64) || defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_ARM)
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {