зеркало из https://github.com/mozilla/pjs.git
Merge from mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
b40bc2a90b
|
@ -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> </td></tr>
|
||||
<tr><td> </td></tr>
|
||||
<tr><td> </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> </td></tr>
|
||||
<tr style="display: none;" language="cs"><td> </td></tr>
|
||||
<tr style="display: none;" language="cs"><td> </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 > </td></tr>
|
||||
<tr id="2" class="nix"><td > </td></tr>
|
||||
<tr id="3" class="ref"><td > </td></tr>
|
||||
<tr><td> </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 > </td></tr>
|
||||
<tr id="2"><td > </td></tr>
|
||||
<tr id="3"><td > </td></tr>
|
||||
<tr><td> </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"><!DOCTYPE html></span>
|
||||
<span><<span class="start-tag">html</span>></span>
|
||||
<span><<span class="start-tag">head</span>></span>
|
||||
<span><<span class="start-tag">title</span>></span><span>Title</span><span></<span class="end-tag">title</span>></span>
|
||||
<span><<span class="start-tag">script</span>></span>
|
||||
var lt = "<";
|
||||
<!--
|
||||
var s = "<script>foo</script>";
|
||||
-->
|
||||
<span class="end-tag"></script></span><span></span><span class="comment"><!-- Not quite optimal highlight there. --></span>
|
||||
<span><<span class="start-tag">style</span>></span>
|
||||
/* </foo> */
|
||||
<span></<span class="end-tag">style</span>></span>
|
||||
<span></<span class="end-tag">head</span>></span>
|
||||
<span><<span class="start-tag">body</span>></span>
|
||||
<span><<span class="start-tag">p</span>></span><span>Entity: <span class="entity"><span>&</span>amp; </span></span><span></<span class="end-tag">p</span>></span>
|
||||
<span><<span class="start-tag">iframe</span>></span><img><span></<span class="end-tag">iframe</span>></span>
|
||||
<span><<span class="start-tag">noscript</span>></span><p>Not para</p><span></<span class="end-tag">noscript</span>></span>
|
||||
<span><<span class="start-tag">svg</span>></span>
|
||||
<span><<span class="start-tag">title</span>></span><span></span><span class="cdata"><![CDATA[bar]]></span><span></span><span></<span class="end-tag">title</span>></span>
|
||||
<span><<span class="start-tag">script</span>></span><span></span><span class="comment"><!-- this is a comment --></span><span></span><span></<span class="end-tag">script</span>></span>
|
||||
<span></<span class="end-tag">svg</span>></span>
|
||||
<span></<span class="end-tag">body</span>></span>
|
||||
<span></<span class="end-tag">html</span>></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"><!DOCTYPE html></span>
|
||||
<span id></span><span><<span class="start-tag">html</span>></span>
|
||||
<span id></span><span><<span class="start-tag">head</span>></span>
|
||||
<span id></span><span><<span class="start-tag">title</span>></span><span>Title</span><span></<span class="end-tag">title</span>></span>
|
||||
<span id></span><span><<span class="start-tag">script</span>></span>
|
||||
<span id></span>var lt = "<";
|
||||
<span id></span><!--
|
||||
<span id></span>var s = "<script>foo</script>";
|
||||
<span id></span>-->
|
||||
<span id></span><span class="end-tag"></script></span><span></span><span class="comment"><!-- Not quite optimal highlight there. --></span>
|
||||
<span id></span><span><<span class="start-tag">style</span>></span>
|
||||
<span id></span>/* </foo> */
|
||||
<span id></span><span></<span class="end-tag">style</span>></span>
|
||||
<span id></span><span></<span class="end-tag">head</span>></span>
|
||||
<span id></span><span><<span class="start-tag">body</span>></span>
|
||||
<span id></span><span><<span class="start-tag">p</span>></span><span>Entity: <span class="entity"><span>&</span>amp; </span></span><span></<span class="end-tag">p</span>></span>
|
||||
<span id></span><span><<span class="start-tag">iframe</span>></span><img><span></<span class="end-tag">iframe</span>></span>
|
||||
<span id></span><span><<span class="start-tag">noscript</span>></span><p>Not para</p><span></<span class="end-tag">noscript</span>></span>
|
||||
<span id></span><span><<span class="start-tag">svg</span>></span>
|
||||
<span id></span><span><<span class="start-tag">title</span>></span><span></span><span class="cdata"><![CDATA[bar]]></span><span></span><span></<span class="end-tag">title</span>></span>
|
||||
<span id></span><span><<span class="start-tag">script</span>></span><span></span><span class="comment"><!-- this is a comment --></span><span></span><span></<span class="end-tag">script</span>></span>
|
||||
<span id></span><span></<span class="end-tag">svg</span>></span>
|
||||
<span id></span><span></<span class="end-tag">body</span>></span>
|
||||
<span id></span><span></<span class="end-tag">html</span>></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"><?xml version="1.0" encoding="utf-8"?></span>
|
||||
<span class="pi"><?foo bar?></span>
|
||||
<span><<span class="start-tag">html</span>></span>
|
||||
<span><<span class="start-tag">head</span>></span>
|
||||
<span><<span class="start-tag">title</span>></span><span>Title</span><span></<span class="end-tag">title</span>></span>
|
||||
<span><<span class="start-tag">script</span>></span>
|
||||
var s = "<span><<span class="start-tag">script</span>></span><span>foo</span><span></<span class="end-tag">script</span>></span>";
|
||||
<span class="comment"><!--
|
||||
var s = "<script>foo</script>";
|
||||
--></span>
|
||||
<span></<span class="end-tag">script</span>></span><span></span>
|
||||
<span><<span class="start-tag">style</span>></span>
|
||||
/* <span><<span class="start-tag">foo</span><span>/</span>></span> */
|
||||
<span></<span class="end-tag">style</span>></span>
|
||||
<span></<span class="end-tag">head</span>></span>
|
||||
<span><<span class="start-tag">body</span>></span>
|
||||
<span><<span class="start-tag">p</span>></span><span>Entity: <span class="entity"><span>&</span>amp; </span></span><span></<span class="end-tag">p</span>></span>
|
||||
<span><<span class="start-tag">iframe</span>></span><span></span><span><<span class="start-tag">img</span>></span><span></<span class="end-tag">iframe</span>></span>
|
||||
<span><<span class="start-tag">noscript</span>></span><span><<span class="start-tag">p</span>></span><span>Not para</span><span></<span class="end-tag">p</span>></span><span></<span class="end-tag">noscript</span>></span>
|
||||
<span><<span class="start-tag">svg</span>></span>
|
||||
<span><<span class="start-tag">title</span>></span><span></span><span class="cdata"><![CDATA[bar]]></span><span></span><span></<span class="end-tag">title</span>></span>
|
||||
<span><<span class="start-tag">script</span>></span><span></span><span class="comment"><!-- this is a comment --></span><span></span><span></<span class="end-tag">script</span>></span>
|
||||
<span></<span class="end-tag">svg</span>></span>
|
||||
<span></<span class="end-tag">body</span>></span>
|
||||
<span></<span class="end-tag">html</span>></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"><?xml version="1.0" encoding="utf-8"?></span>
|
||||
<span id></span><span class="pi"><?foo bar?></span>
|
||||
<span id></span><span><<span class="start-tag">html</span>></span>
|
||||
<span id></span><span><<span class="start-tag">head</span>></span>
|
||||
<span id></span><span><<span class="start-tag">title</span>></span><span>Title</span><span></<span class="end-tag">title</span>></span>
|
||||
<span id></span><span><<span class="start-tag">script</span>></span>
|
||||
<span id></span>var s = "<span><<span class="start-tag">script</span>></span><span>foo</span><span></<span class="end-tag">script</span>></span>";
|
||||
<span id></span><span class="comment"><!--
|
||||
<span id></span>var s = "<script>foo</script>";
|
||||
<span id></span>--></span>
|
||||
<span id></span><span></<span class="end-tag">script</span>></span><span></span>
|
||||
<span id></span><span><<span class="start-tag">style</span>></span>
|
||||
<span id></span>/* <span><<span class="start-tag">foo</span><span>/</span>></span> */
|
||||
<span id></span><span></<span class="end-tag">style</span>></span>
|
||||
<span id></span><span></<span class="end-tag">head</span>></span>
|
||||
<span id></span><span><<span class="start-tag">body</span>></span>
|
||||
<span id></span><span><<span class="start-tag">p</span>></span><span>Entity: <span class="entity"><span>&</span>amp; </span></span><span></<span class="end-tag">p</span>></span>
|
||||
<span id></span><span><<span class="start-tag">iframe</span>></span><span></span><span><<span class="start-tag">img</span>></span><span></<span class="end-tag">iframe</span>></span>
|
||||
<span id></span><span><<span class="start-tag">noscript</span>></span><span><<span class="start-tag">p</span>></span><span>Not para</span><span></<span class="end-tag">p</span>></span><span></<span class="end-tag">noscript</span>></span>
|
||||
<span id></span><span><<span class="start-tag">svg</span>></span>
|
||||
<span id></span><span><<span class="start-tag">title</span>></span><span></span><span class="cdata"><![CDATA[bar]]></span><span></span><span></<span class="end-tag">title</span>></span>
|
||||
<span id></span><span><<span class="start-tag">script</span>></span><span></span><span class="comment"><!-- this is a comment --></span><span></span><span></<span class="end-tag">script</span>></span>
|
||||
<span id></span><span></<span class="end-tag">svg</span>></span>
|
||||
<span id></span><span></<span class="end-tag">body</span>></span>
|
||||
<span id></span><span></<span class="end-tag">html</span>></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"><!DOCTYPE html></span>
|
||||
XX<span class="error">&</span>XX
|
||||
XX<span class="error">&</span>nXX
|
||||
XX<span class="error">&</span>noXX
|
||||
XX<span class="error entity">&not</span>XX
|
||||
XX<span class="error entity">&noti</span>XX
|
||||
XX<span class="error entity">&notin</span>XX
|
||||
XX<span class="error">&</span>;XX
|
||||
XX<span class="error">&</span>n;XX
|
||||
XX<span class="error">&</span>no;XX
|
||||
XX<span class="entity">&not;</span>XX
|
||||
XX<span class="error entity">&noti</span>;XX
|
||||
XX<span class="entity">&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"><!DOCTYPE html></span>
|
||||
<span id></span>XX<span class="error">&</span>XX
|
||||
<span id></span>XX<span class="error">&</span>nXX
|
||||
<span id></span>XX<span class="error">&</span>noXX
|
||||
<span id></span>XX<span class="error entity">&not</span>XX
|
||||
<span id></span>XX<span class="error entity">&noti</span>XX
|
||||
<span id></span>XX<span class="error entity">&notin</span>XX
|
||||
<span id></span>XX<span class="error">&</span>;XX
|
||||
<span id></span>XX<span class="error">&</span>n;XX
|
||||
<span id></span>XX<span class="error">&</span>no;XX
|
||||
<span id></span>XX<span class="entity">&not;</span>XX
|
||||
<span id></span>XX<span class="error entity">&noti</span>;XX
|
||||
<span id></span>XX<span class="entity">&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"><!--></span> <span class="error comment"><!X></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"><!--></span> <span class="error comment"><!X></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]
|
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче