--- a/Makefile.in
+++ b/Makefile.in
@@ -193,9 +193,9 @@ ifdef MOZILLA_OFFICIAL
cd $(DIST)/bin; ./shlibsign.exe -v -i softokn3.dll
cd $(DIST)/bin; ./shlibsign.exe -v -i freebl3.dll
endif # MOZILLA_OFFICIAL
deliver: splitsymbols rebase signnss
endif # WINNT
-BUILDID = $(shell cat $(DEPTH)/config/build_number)
+BUILDID = $(shell $(PYTHON) $(srcdir)/config/printconfigsetting.py $(DIST)/bin/application.ini App BuildID)
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -60,45 +60,35 @@ AB_CD = en-US
DEFINES += -DAB_CD=$(AB_CD)
APP_VERSION = $(shell cat $(srcdir)/../config/version.txt)
DEFINES += -DAPP_VERSION="$(APP_VERSION)"
APP_UA_NAME = $(shell echo $(MOZ_APP_DISPLAYNAME) | sed -e's/[^A-Za-z]//g')
DEFINES += -DAPP_UA_NAME="$(APP_UA_NAME)"
-ifdef LIBXUL_SDK
-# Build application.ini for a XULRunner app
-
DIST_FILES = application.ini
-# GRE_BUILD_ID is only available in nsBuildID.h in a form that we can't use
-# directly. So munge it. Beware makefile and shell escaping
-AWK_EXPR = '/\#define GRE_BUILD_ID/ { gsub(/"/, "", $$3); print $$3 }'
-AWK_CMD = awk $(AWK_EXPR) < $(LIBXUL_DIST)/include/nsBuildID.h
-
-GRE_BUILD_ID = $(shell $(AWK_CMD))
+GRE_MILESTONE = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build Milestone)
+GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build BuildID)
-DEFINES += -DGRE_BUILD_ID=$(GRE_BUILD_ID)
-
-include $(topsrcdir)/config/rules.mk
+DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
-else
+ifndef LIBXUL_SDK
# Build a binary bootstrapping with XRE_main
-MOZILLA_INTERNAL_API = 1
-
ifeq ($(USE_SHORT_LIBNAME), 1)
PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
else
PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
endif
REQUIRES = \
xpcom \
+ string \
xulapp \
$(NULL)
CPPSRCS = nsBrowserApp.cpp
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
ifdef BUILD_STATIC_LIBS
@@ -115,21 +105,28 @@ else
EXTRA_DSO_LIBS += xul
endif
endif
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
TK_LIBS := -framework Cocoa $(TK_LIBS)
endif
+ifdef MOZ_ENABLE_LIBXUL
+APP_XPCOM_LIBS = $(XPCOM_GLUE_LDOPTS)
+else
+MOZILLA_INTERNAL_API = 1
+APP_XPCOM_LIBS = $(XPCOM_LIBS)
+endif
+
LIBS += \
$(STATIC_COMPONENTS_LINKER_PATH) \
$(EXTRA_DSO_LIBS) \
$(MOZ_JS_LIBS) \
- $(XPCOM_LIBS) \
+ $(APP_XPCOM_LIBS) \
$(NSPR_LIBS) \
$(TK_LIBS) \
$(NULL)
# Add explicit X11 dependency when building against X11 toolkits
ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
LIBS += $(XLDFLAGS) $(XLIBS)
ifdef MOZ_ENABLE_CAIRO_GFX
--- a/browser/app/application.ini
+++ b/browser/app/application.ini
@@ -35,23 +35,25 @@
;
; ***** END LICENSE BLOCK *****
#filter substitution
[App]
Vendor=Mozilla
Name=Firefox
Version=@APP_VERSION@
-BuildID=@BUILD_ID@
+BuildID=@GRE_BUILDID@
Copyright=Copyright (c) 1998 - 2007 mozilla.org
ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
[Gecko]
-MinVersion=@GRE_BUILD_ID@
-MaxVersion=@GRE_BUILD_ID@
+MinVersion=@GRE_MILESTONE@
+MaxVersion=@GRE_MILESTONE@
[XRE]
EnableProfileMigrator=1
EnableExtensionManager=1
[Crash Reporter]
-Enabled=0
+#if MOZILLA_OFFICIAL
+Enabled=1
+#endif
ServerURL=https://crash-reports.mozilla.com/submit
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -36,42 +36,62 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsXULAppAPI.h"
#ifdef XP_WIN
#include <windows.h>
#include <stdlib.h>
#endif
-#include "nsBuildID.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "nsCOMPtr.h"
+#include "nsILocalFile.h"
+#include "nsStringGlue.h"
+
+static void Output(const char *fmt, ... )
+{
+ va_list ap;
+ va_start(ap, fmt);
-static const nsXREAppData kAppData = {
- sizeof(nsXREAppData),
- nsnull,
- "Mozilla",
- "Firefox",
- NS_STRINGIFY(APP_VERSION),
- NS_STRINGIFY(BUILD_ID),
- "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
- "Copyright (c) 1998 - 2007 mozilla.org",
- NS_XRE_ENABLE_PROFILE_MIGRATOR |
- NS_XRE_ENABLE_EXTENSION_MANAGER
-#if defined(MOZILLA_OFFICIAL)
- | NS_XRE_ENABLE_CRASH_REPORTER
+#if defined(XP_WIN) && !MOZ_WINCONSOLE
+ char msg[2048];
+
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+
+ MessageBox(NULL, msg, "XULRunner", MB_OK | MB_ICONERROR);
+#else
+ vfprintf(stderr, fmt, ap);
#endif
-,
- nsnull, // xreDirectory
- nsnull, // minVersion
- nsnull, // maxVersion
- "https://crash-reports.mozilla.com/submit"
-};
+
+ va_end(ap);
+}
int main(int argc, char* argv[])
{
- return XRE_main(argc, argv, &kAppData);
+ nsCOMPtr<nsILocalFile> appini;
+ nsresult rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appini));
+ if (NS_FAILED(rv)) {
+ Output("Couldn't calculate the application directory.");
+ return 255;
+ }
+ appini->SetNativeLeafName(NS_LITERAL_CSTRING("application.ini"));
+
+ nsXREAppData *appData;
+ rv = XRE_CreateAppData(appini, &appData);
+ if (NS_FAILED(rv)) {
+ Output("Couldn't read application.ini");
+ return 255;
+ }
+
+ int result = XRE_main(argc, argv, appData);
+ XRE_FreeAppData(appData);
+ return result;
}
#if defined( XP_WIN ) && defined( WIN32 ) && !defined(__GNUC__)
// We need WinMain in order to not be a console app. This function is
// unused if we are a console application.
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
{
// Do the real work.
--- a/browser/installer/unix/packages-static
+++ b/browser/installer/unix/packages-static
@@ -40,16 +40,18 @@ bin/libnspr4.so
bin/libxul.so
bin/components/libxpinstall.so
bin/components/libjar50.so
[browser]
; [Base Browser Files]
bin/@MOZ_APP_NAME@-bin
bin/@MOZ_APP_NAME@
+bin/application.ini
+bin/platform.ini
bin/mozilla-xremote-client
bin/run-mozilla.sh
bin/plugins/libnullplugin.so
bin/res/cmessage.txt
bin/res/effective_tld_names.dat
bin/xpicleanup
; [Components]
--- a/browser/installer/windows/packages-static
+++ b/browser/installer/windows/packages-static
@@ -43,16 +43,18 @@ bin\components\jar50.dll
bin\Microsoft.VC80.CRT.manifest
bin\msvcm80.dll
bin\msvcp80.dll
bin\msvcr80.dll
[browser]
; [Base Browser Files]
bin\@MOZ_APP_NAME@.exe
+bin\application.ini
+bin\platform.ini
bin\plugins\npnul32.dll
bin\res\cmessage.txt
bin\res\effective_tld_names.dat
bin\xpicleanup.exe
bin\LICENSE
bin\README.txt
; [Components]
--- a/client.mk
+++ b/client.mk
@@ -452,16 +452,17 @@ endif
AUTOCONF := autoconf
MKDIR := mkdir
SH := /bin/sh
ifndef MAKE
MAKE := gmake
endif
PERL ?= perl
+PYTHON ?= python
CONFIG_GUESS_SCRIPT := $(wildcard $(TOPSRCDIR)/build/autoconf/config.guess)
ifdef CONFIG_GUESS_SCRIPT
CONFIG_GUESS = $(shell $(CONFIG_GUESS_SCRIPT))
else
_IS_FIRST_CHECKOUT := 1
endif
@@ -935,17 +936,17 @@ else
# After First Checkout
#####################################################
# Build date unification
ifdef MOZ_UNIFY_BDATE
ifndef MOZ_BUILD_DATE
ifdef MOZ_BUILD_PROJECTS
-MOZ_BUILD_DATE = $(shell $(PERL) -I$(TOPSRCDIR)/config $(TOPSRCDIR)/config/bdate.pl)
+MOZ_BUILD_DATE = $(shell $(PYTHON) $(TOPSRCDIR)/toolkit/xre/make-platformini.py --print-buildid)
export MOZ_BUILD_DATE
endif
endif
endif
#####################################################
# Preflight, before building any project
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -54,19 +54,16 @@ HOST_PROGRAM = nsinstall$(HOST_BIN_SUFFI
HOST_CSRCS = nsinstall.c pathsub.c
endif
endif
PLSRCS = nfspwd.pl revdepth.pl
TARGETS = $(HOST_PROGRAM) $(PLSRCS:.pl=) $(SIMPLE_PROGRAMS)
-# Generate the build number on the fly.
-TARGETS += build_number nsBuildID.h
-
ifndef CROSS_COMPILE
ifdef USE_ELF_DYNSTR_GC
TARGETS += elf-dynstr-gc
endif
endif
# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
# a recursive rule for finding nsinstall and the Perl scripts.
@@ -91,17 +88,16 @@ NO_INSTALL=1
include $(topsrcdir)/config/rules.mk
ifeq ($(OS_CONFIG),SunOS4.1)
NSPR_CFLAGS += -I$(srcdir)/../nsprpub/pr/include/md
endif
HEADERS = \
- nsBuildID.h \
$(DEPTH)/mozilla-config.h \
$(srcdir)/nsStaticComponents.h \
$(NULL)
export:: $(TARGETS) $(HEADERS)
$(INSTALL) $(IFLAGS1) $(HEADERS) $(DIST)/include
-rm -f $(FINAL_LINK_COMPS) $(FINAL_LINK_LIBS) $(FINAL_LINK_COMP_NAMES)
-rm -f $(DIST)/bin/chrome/chromelist.txt
@@ -118,45 +114,22 @@ export::
-DMOZ_ENABLE_LIBXUL=$(MOZ_ENABLE_LIBXUL) \
-DMOZ_NATIVE_ZLIB=$(MOZ_NATIVE_ZLIB) \
-DMOZ_NATIVE_PNG=$(MOZ_NATIVE_PNG) \
-DMOZ_NATIVE_JPEG=$(MOZ_NATIVE_JPEG) \
$(srcdir)/system-headers | $(PERL) $(topsrcdir)/nsprpub/config/make-system-wrappers.pl system_wrappers
$(INSTALL) system_wrappers $(DIST)/include
endif
-# we don't use an explicit dependency here because then we would
-# regenerate nsBuildID.h during the make install phase and that would
-# be bad.
install::
- @if test ! -f nsBuildID.h; then\
- echo "You must have done at least a make export before trying to do a make install."; \
- echo "(nsBuildID.h is missing.)"; \
- exit 1; \
- fi;
$(SYSINSTALL) $(IFLAGS1) $(DEPTH)/mozilla-config.h $(DESTDIR)$(includedir)
-GARBAGE += build_number nsBuildID \
+GARBAGE += \
$(FINAL_LINK_COMPS) $(FINAL_LINK_LIBS) $(FINAL_LINK_COMP_NAMES)
-ifneq (,$(BUILD_OFFICIAL)$(MOZILLA_OFFICIAL))
-_BN_OFFICIAL=1
-else
-_BN_OFFICIAL=
-endif
-
-build_number: FORCE
- $(PERL) -I$(srcdir) $(srcdir)/bdate.pl $@ $(_BN_OFFICIAL)
-
-nsBuildID.h: nsBuildID.h.in build_number $(srcdir)/milestone.txt Makefile
- $(RM) $@
- MOZ_MILESTONE_RELEASE=$(MOZ_MILESTONE_RELEASE); \
- export MOZ_MILESTONE_RELEASE; \
- $(PERL) -I$(srcdir) $(srcdir)/aboutime.pl -m $(srcdir)/milestone.txt $@ build_number $(srcdir)/nsBuildID.h.in
-
ifndef CROSS_COMPILE
ifdef USE_ELF_DYNSTR_GC
elf-dynstr-gc: elf-dynstr-gc.c Makefile Makefile.in
$(CC) $(COMPILE_CFLAGS) $(GLIB_CFLAGS) -o $@ $< $(LDFLAGS) $(GLIB_LIBS)
endif
endif
FORCE:
deleted file mode 100755
--- a/config/aboutime.pl
+++ /dev/null
@@ -1,24 +0,0 @@
-
-use strict;
-use Getopt::Std;
-require mozBDate;
-require "Moz/Milestone.pm";
-
-my $mfile;
-getopts('m:');
-if (defined($::opt_m)) {
- $mfile = $::opt_m;
-}
-
-my $outfile = $ARGV[0];
-my $build_num_file = $ARGV[1];
-my $infile = "";
-
-$infile = $ARGV[2] if ("$ARGV[2]" ne "");
-
-if (defined($mfile)) {
- my $milestone = &Moz::Milestone::getOfficialMilestone($mfile);
- &mozBDate::SetMilestone($milestone);
-}
-&mozBDate::SubstituteBuildNumber($outfile, $build_num_file, $infile);
-
deleted file mode 100644
--- a/config/bdate.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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"),
- * 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 ***** */
-
-/*
-**
-** bdate.c: Possibly cross-platform date-based build number
-** generator. Output is YYJJJ, where YY == 2-digit
-** year, and JJJ is the Julian date (day of the year).
-**
-** Author: briano@netscape.com
-**
-*/
-
-#include <stdio.h>
-#include <time.h>
-
-#ifdef SUNOS4
-#include "sunos4.h"
-#endif
-
-void main(void)
-{
- time_t t = time(NULL);
- struct tm *tms;
-
- tms = localtime(&t);
- printf("500%02d%03d%02d\n", tms->tm_year, 1+tms->tm_yday, tms->tm_hour);
- exit(0);
-}
deleted file mode 100755
--- a/config/bdate.pl
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# 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"),
-# 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 *****
-
-use mozBDate;
-
-# Both "generate" args are optional
-$file = $ARGV[0] if ("$ARGV[0]" ne "");
-$official = 1 if ("$ARGV[1]" ne "");
-&mozBDate::UpdateBuildNumber($file, $official);
-
deleted file mode 100644
--- a/config/build-number.pl
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# ***** 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 Communicator client code.
-#
-# The Initial Developer of the Original Code is
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# 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"),
-# 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 *****
-
-my $progname = $0;
-my $contents;
-
-# this script needs to be run in config
-my $numberfile = "build_number";
-
-# This is the preferences file that gets read and written.
-
-open(NUMBER, "<$numberfile") || die "no build_number file\n";
-
-while ( <NUMBER> ) {
- $build_number = $_
-}
-close (NUMBER);
-
-chop($build_number);
-
--- a/config/config.mk
+++ b/config/config.mk
@@ -866,22 +866,16 @@ EXPAND_LOCALE_SRCDIR = $(if $(filter en-
ifdef relativesrcdir
LOCALE_SRCDIR = $(call EXPAND_LOCALE_SRCDIR,$(relativesrcdir))
endif
ifdef LOCALE_SRCDIR
MAKE_JARS_FLAGS += -c $(LOCALE_SRCDIR)
endif
-#
-# Add BUILD_ID to set of DEFINES
-#
-BUILD_ID := $(shell cat $(DEPTH)/config/build_number)
-DEFINES += -DBUILD_ID=$(BUILD_ID)
-
ifeq (,$(filter WINCE WINNT OS2,$(OS_ARCH)))
RUN_TEST_PROGRAM = $(DIST)/bin/run-mozilla.sh
endif
#
# Java macros
#
new file mode 100644
--- /dev/null
+++ b/config/configobj.py
@@ -0,0 +1,2279 @@
+# configobj.py
+# A config file reader/writer that supports nested sections in config files.
+# Copyright (C) 2005-2006 Michael Foord, Nicola Larosa
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+# nico AT tekNico DOT net
+
+# ConfigObj 4
+# http://www.voidspace.org.uk/python/configobj.html
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# For information about bugfixes, updates and support, please join the
+# ConfigObj mailing list:
+# http://lists.sourceforge.net/lists/listinfo/configobj-develop
+# Comments, suggestions and bug reports welcome.
+
+from __future__ import generators
+
+import sys
+INTP_VER = sys.version_info[:2]
+if INTP_VER < (2, 2):
+ raise RuntimeError("Python v.2.2 or later needed")
+
+import os, re
+compiler = None
+try:
+ import compiler
+except ImportError:
+ # for IronPython
+ pass
+from types import StringTypes
+from warnings import warn
+try:
+ from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
+except ImportError:
+ # Python 2.2 does not have these
+ # UTF-8
+ BOM_UTF8 = '\xef\xbb\xbf'
+ # UTF-16, little endian
+ BOM_UTF16_LE = '\xff\xfe'
+ # UTF-16, big endian
+ BOM_UTF16_BE = '\xfe\xff'
+ if sys.byteorder == 'little':
+ # UTF-16, native endianness
+ BOM_UTF16 = BOM_UTF16_LE
+ else:
+ # UTF-16, native endianness
+ BOM_UTF16 = BOM_UTF16_BE
+
+# A dictionary mapping BOM to
+# the encoding to decode with, and what to set the
+# encoding attribute to.
+BOMS = {
+ BOM_UTF8: ('utf_8', None),
+ BOM_UTF16_BE: ('utf16_be', 'utf_16'),
+ BOM_UTF16_LE: ('utf16_le', 'utf_16'),
+ BOM_UTF16: ('utf_16', 'utf_16'),
+ }
+# All legal variants of the BOM codecs.
+# TODO: the list of aliases is not meant to be exhaustive, is there a
+# better way ?
+BOM_LIST = {
+ 'utf_16': 'utf_16',
+ 'u16': 'utf_16',
+ 'utf16': 'utf_16',
+ 'utf-16': 'utf_16',
+ 'utf16_be': 'utf16_be',
+ 'utf_16_be': 'utf16_be',
+ 'utf-16be': 'utf16_be',
+ 'utf16_le': 'utf16_le',
+ 'utf_16_le': 'utf16_le',
+ 'utf-16le': 'utf16_le',
+ 'utf_8': 'utf_8',
+ 'u8': 'utf_8',
+ 'utf': 'utf_8',
+ 'utf8': 'utf_8',
+ 'utf-8': 'utf_8',
+ }
+
+# Map of encodings to the BOM to write.
+BOM_SET = {
+ 'utf_8': BOM_UTF8,
+ 'utf_16': BOM_UTF16,
+ 'utf16_be': BOM_UTF16_BE,
+ 'utf16_le': BOM_UTF16_LE,
+ None: BOM_UTF8
+ }
+
+try:
+ from validate import VdtMissingValue
+except ImportError:
+ VdtMissingValue = None
+
+try:
+ enumerate
+except NameError:
+ def enumerate(obj):
+ """enumerate for Python 2.2."""
+ i = -1
+ for item in obj:
+ i += 1
+ yield i, item
+
+try:
+ True, False
+except NameError:
+ True, False = 1, 0
+
+
+__version__ = '4.4.0'
+
+__revision__ = '$Id: configobj.py,v 3.5 2007/07/02 18:20:24 benjamin%smedbergs.us Exp $'
+
+__docformat__ = "restructuredtext en"
+
+__all__ = (
+ '__version__',
+ 'DEFAULT_INDENT_TYPE',
+ 'DEFAULT_INTERPOLATION',
+ 'ConfigObjError',
+ 'NestingError',
+ 'ParseError',
+ 'DuplicateError',
+ 'ConfigspecError',
+ 'ConfigObj',
+ 'SimpleVal',
+ 'InterpolationError',
+ 'InterpolationLoopError',
+ 'MissingInterpolationOption',
+ 'RepeatSectionError',
+ 'UnreprError',
+ 'UnknownType',
+ '__docformat__',
+ 'flatten_errors',
+)
+
+DEFAULT_INTERPOLATION = 'configparser'
+DEFAULT_INDENT_TYPE = ' '
+MAX_INTERPOL_DEPTH = 10
+
+OPTION_DEFAULTS = {
+ 'interpolation': True,
+ 'raise_errors': False,
+ 'list_values': True,
+ 'create_empty': False,
+ 'file_error': False,
+ 'configspec': None,
+ 'stringify': True,
+ # option may be set to one of ('', ' ', '\t')
+ 'indent_type': None,
+ 'encoding': None,
+ 'default_encoding': None,
+ 'unrepr': False,
+ 'write_empty_values': False,
+}
+
+
+def getObj(s):
+ s = "a=" + s
+ if compiler is None:
+ raise ImportError('compiler module not available')
+ p = compiler.parse(s)
+ return p.getChildren()[1].getChildren()[0].getChildren()[1]
+
+class UnknownType(Exception):
+ pass
+
+class Builder:
+
+ def build(self, o):
+ m = getattr(self, 'build_' + o.__class__.__name__, None)
+ if m is None:
+ raise UnknownType(o.__class__.__name__)
+ return m(o)
+
+ def build_List(self, o):
+ return map(self.build, o.getChildren())
+
+ def build_Const(self, o):
+ return o.value
+
+ def build_Dict(self, o):
+ d = {}
+ i = iter(map(self.build, o.getChildren()))
+ for el in i:
+ d[el] = i.next()
+ return d
+
+ def build_Tuple(self, o):
+ return tuple(self.build_List(o))
+
+ def build_Name(self, o):
+ if o.name == 'None':
+ return None
+ if o.name == 'True':
+ return True
+ if o.name == 'False':
+ return False
+
+ # An undefinted Name
+ raise UnknownType('Undefined Name')
+
+ def build_Add(self, o):
+ real, imag = map(self.build_Const, o.getChildren())
+ try:
+ real = float(real)
+ except TypeError:
+ raise UnknownType('Add')
+ if not isinstance(imag, complex) or imag.real != 0.0:
+ raise UnknownType('Add')
+ return real+imag
+
+ def build_Getattr(self, o):
+ parent = self.build(o.expr)
+ return getattr(parent, o.attrname)
+
+ def build_UnarySub(self, o):
+ return -self.build_Const(o.getChildren()[0])
+
+ def build_UnaryAdd(self, o):
+ return self.build_Const(o.getChildren()[0])
+
+def unrepr(s):
+ if not s:
+ return s
+ return Builder().build(getObj(s))
+
+def _splitlines(instring):
+ """Split a string on lines, without losing line endings or truncating."""
+
+
+class ConfigObjError(SyntaxError):
+ """
+ This is the base class for all errors that ConfigObj raises.
+ It is a subclass of SyntaxError.
+ """
+ def __init__(self, message='', line_number=None, line=''):
+ self.line = line
+ self.line_number = line_number
+ self.message = message
+ SyntaxError.__init__(self, message)
+
+class NestingError(ConfigObjError):
+ """
+ This error indicates a level of nesting that doesn't match.
+ """
+
+class ParseError(ConfigObjError):
+ """
+ This error indicates that a line is badly written.
+ It is neither a valid ``key = value`` line,
+ nor a valid section marker line.
+ """
+
+class DuplicateError(ConfigObjError):
+ """
+ The keyword or section specified already exists.
+ """
+
+class ConfigspecError(ConfigObjError):
+ """
+ An error occured whilst parsing a configspec.
+ """
+
+class InterpolationError(ConfigObjError):
+ """Base class for the two interpolation errors."""
+
+class InterpolationLoopError(InterpolationError):
+ """Maximum interpolation depth exceeded in string interpolation."""
+
+ def __init__(self, option):
+ InterpolationError.__init__(
+ self,
+ 'interpolation loop detected in value "%s".' % option)
+
+class RepeatSectionError(ConfigObjError):
+ """
+ This error indicates additional sections in a section with a
+ ``__many__`` (repeated) section.
+ """
+
+class MissingInterpolationOption(InterpolationError):
+ """A value specified for interpolation was missing."""
+
+ def __init__(self, option):
+ InterpolationError.__init__(
+ self,
+ 'missing option "%s" in interpolation.' % option)
+
+class UnreprError(ConfigObjError):
+ """An error parsing in unrepr mode."""
+
+
+class InterpolationEngine(object):
+ """
+ A helper class to help perform string interpolation.
+
+ This class is an abstract base class; its descendants perform
+ the actual work.
+ """
+
+ # compiled regexp to use in self.interpolate()
+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+
+ def __init__(self, section):
+ # the Section instance that "owns" this engine
+ self.section = section
+
+ def interpolate(self, key, value):
+ def recursive_interpolate(key, value, section, backtrail):
+ """The function that does the actual work.
+
+ ``value``: the string we're trying to interpolate.
+ ``section``: the section in which that string was found
+ ``backtrail``: a dict to keep track of where we've been,
+ to detect and prevent infinite recursion loops
+
+ This is similar to a depth-first-search algorithm.
+ """
+ # Have we been here already?
+ if backtrail.has_key((key, section.name)):
+ # Yes - infinite loop detected
+ raise InterpolationLoopError(key)
+ # Place a marker on our backtrail so we won't come back here again
+ backtrail[(key, section.name)] = 1
+
+ # Now start the actual work
+ match = self._KEYCRE.search(value)
+ while match:
+ # The actual parsing of the match is implementation-dependent,
+ # so delegate to our helper function
+ k, v, s = self._parse_match(match)
+ if k is None:
+ # That's the signal that no further interpolation is needed
+ replacement = v
+ else:
+ # Further interpolation may be needed to obtain final value
+ replacement = recursive_interpolate(k, v, s, backtrail)
+ # Replace the matched string with its final value
+ start, end = match.span()
+ value = ''.join((value[:start], replacement, value[end:]))
+ new_search_start = start + len(replacement)
+ # Pick up the next interpolation key, if any, for next time
+ # through the while loop
+ match = self._KEYCRE.search(value, new_search_start)
+
+ # Now safe to come back here again; remove marker from backtrail
+ del backtrail[(key, section.name)]
+
+ return value
+
+ # Back in interpolate(), all we have to do is kick off the recursive
+ # function with appropriate starting values
+ value = recursive_interpolate(key, value, self.section, {})
+ return value
+
+ def _fetch(self, key):
+ """Helper function to fetch values from owning section.
+
+ Returns a 2-tuple: the value, and the section where it was found.
+ """
+ # switch off interpolation before we try and fetch anything !
+ save_interp = self.section.main.interpolation
+ self.section.main.interpolation = False
+
+ # Start at section that "owns" this InterpolationEngine
+ current_section = self.section
+ while True:
+ # try the current section first
+ val = current_section.get(key)
+ if val is not None:
+ break
+ # try "DEFAULT" next
+ val = current_section.get('DEFAULT', {}).get(key)
+ if val is not None:
+ break
+ # move up to parent and try again
+ # top-level's parent is itself
+ if current_section.parent is current_section:
+ # reached top level, time to give up
+ break
+ current_section = current_section.parent
+
+ # restore interpolation to previous value before returning
+ self.section.main.interpolation = save_interp
+ if val is None:
+ raise MissingInterpolationOption(key)
+ return val, current_section
+
+ def _parse_match(self, match):
+ """Implementation-dependent helper function.
+
+ Will be passed a match object corresponding to the interpolation
+ key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
+ key in the appropriate config file section (using the ``_fetch()``
+ helper function) and return a 3-tuple: (key, value, section)
+
+ ``key`` is the name of the key we're looking for
+ ``value`` is the value found for that key
+ ``section`` is a reference to the section where it was found
+
+ ``key`` and ``section`` should be None if no further
+ interpolation should be performed on the resulting value
+ (e.g., if we interpolated "$$" and returned "$").
+ """
+ raise NotImplementedError
+
+
+class ConfigParserInterpolation(InterpolationEngine):
+ """Behaves like ConfigParser."""
+ _KEYCRE = re.compile(r"%\(([^)]*)\)s")
+
+ def _parse_match(self, match):
+ key = match.group(1)
+ value, section = self._fetch(key)
+ return key, value, section
+
+
+class TemplateInterpolation(InterpolationEngine):
+ """Behaves like string.Template."""
+ _delimiter = '$'
+ _KEYCRE = re.compile(r"""
+ \$(?:
+ (?P<escaped>\$) | # Two $ signs
+ (?P<named>[_a-z][_a-z0-9]*) | # $name format
+ {(?P<braced>[^}]*)} # ${name} format
+ )
+ """, re.IGNORECASE | re.VERBOSE)
+
+ def _parse_match(self, match):
+ # Valid name (in or out of braces): fetch value from section
+ key = match.group('named') or match.group('braced')
+ if key is not None:
+ value, section = self._fetch(key)
+ return key, value, section
+ # Escaped delimiter (e.g., $$): return single delimiter
+ if match.group('escaped') is not None:
+ # Return None for key and section to indicate it's time to stop
+ return None, self._delimiter, None
+ # Anything else: ignore completely, just return it unchanged
+ return None, match.group(), None
+
+interpolation_engines = {
+ 'configparser': ConfigParserInterpolation,
+ 'template': TemplateInterpolation,
+}
+
+class Section(dict):
+ """
+ A dictionary-like object that represents a section in a config file.
+
+ It does string interpolation if the 'interpolation' attribute
+ of the 'main' object is set to True.
+
+ Interpolation is tried first from this object, then from the 'DEFAULT'
+ section of this object, next from the parent and its 'DEFAULT' section,
+ and so on until the main object is reached.
+
+ A Section will behave like an ordered dictionary - following the
+ order of the ``scalars`` and ``sections`` attributes.
+ You can use this to change the order of members.
+
+ Iteration follows the order: scalars, then sections.
+ """
+
+ def __init__(self, parent, depth, main, indict=None, name=None):
+ """
+ * parent is the section above
+ * depth is the depth level of this section
+ * main is the main ConfigObj
+ * indict is a dictionary to initialise the section with
+ """
+ if indict is None:
+ indict = {}
+ dict.__init__(self)
+ # used for nesting level *and* interpolation
+ self.parent = parent
+ # used for the interpolation attribute
+ self.main = main
+ # level of nesting depth of this Section
+ self.depth = depth
+ # the sequence of scalar values in this Section
+ self.scalars = []
+ # the sequence of sections in this Section
+ self.sections = []
+ # purely for information
+ self.name = name
+ # for comments :-)
+ self.comments = {}
+ self.inline_comments = {}
+ # for the configspec
+ self.configspec = {}
+ self._order = []
+ self._configspec_comments = {}
+ self._configspec_inline_comments = {}
+ self._cs_section_comments = {}
+ self._cs_section_inline_comments = {}
+ # for defaults
+ self.defaults = []
+ #
+ # we do this explicitly so that __setitem__ is used properly
+ # (rather than just passing to ``dict.__init__``)
+ for entry in indict:
+ self[entry] = indict[entry]
+
+ def _interpolate(self, key, value):
+ try:
+ # do we already have an interpolation engine?
+ engine = self._interpolation_engine
+ except AttributeError:
+ # not yet: first time running _interpolate(), so pick the engine
+ name = self.main.interpolation
+ if name == True: # note that "if name:" would be incorrect here
+ # backwards-compatibility: interpolation=True means use default
+ name = DEFAULT_INTERPOLATION
+ name = name.lower() # so that "Template", "template", etc. all work
+ class_ = interpolation_engines.get(name, None)
+ if class_ is None:
+ # invalid value for self.main.interpolation
+ self.main.interpolation = False
+ return value
+ else:
+ # save reference to engine so we don't have to do this again
+ engine = self._interpolation_engine = class_(self)
+ # let the engine do the actual work
+ return engine.interpolate(key, value)
+
+ def __getitem__(self, key):
+ """Fetch the item and do string interpolation."""
+ val = dict.__getitem__(self, key)
+ if self.main.interpolation and isinstance(val, StringTypes):
+ return self._interpolate(key, val)
+ return val
+
+ def __setitem__(self, key, value, unrepr=False):
+ """
+ Correctly set a value.
+
+ Making dictionary values Section instances.
+ (We have to special case 'Section' instances - which are also dicts)
+
+ Keys must be strings.
+ Values need only be strings (or lists of strings) if
+ ``main.stringify`` is set.
+
+ `unrepr`` must be set when setting a value to a dictionary, without
+ creating a new sub-section.
+ """
+ if not isinstance(key, StringTypes):
+ raise ValueError, 'The key "%s" is not a string.' % key
+ # add the comment
+ if not self.comments.has_key(key):
+ self.comments[key] = []
+ self.inline_comments[key] = ''
+ # remove the entry from defaults
+ if key in self.defaults:
+ self.defaults.remove(key)
+ #
+ if isinstance(value, Section):
+ if not self.has_key(key):
+ self.sections.append(key)
+ dict.__setitem__(self, key, value)
+ elif isinstance(value, dict) and not unrepr:
+ # First create the new depth level,
+ # then create the section
+ if not self.has_key(key):
+ self.sections.append(key)
+ new_depth = self.depth + 1
+ dict.__setitem__(
+ self,
+ key,
+ Section(
+ self,
+ new_depth,
+ self.main,
+ indict=value,
+ name=key))
+ else:
+ if not self.has_key(key):
+ self.scalars.append(key)
+ if not self.main.stringify:
+ if isinstance(value, StringTypes):
+ pass
+ elif isinstance(value, (list, tuple)):
+ for entry in value:
+ if not isinstance(entry, StringTypes):
+ raise TypeError, (
+ 'Value is not a string "%s".' % entry)
+ else:
+ raise TypeError, 'Value is not a string "%s".' % value
+ dict.__setitem__(self, key, value)
+
+ def __delitem__(self, key):
+ """Remove items from the sequence when deleting."""
+ dict. __delitem__(self, key)
+ if key in self.scalars:
+ self.scalars.remove(key)
+ else:
+ self.sections.remove(key)
+ del self.comments[key]
+ del self.inline_comments[key]
+
+ def get(self, key, default=None):
+ """A version of ``get`` that doesn't bypass string interpolation."""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def update(self, indict):
+ """
+ A version of update that uses our ``__setitem__``.
+ """
+ for entry in indict:
+ self[entry] = indict[entry]
+
+ def pop(self, key, *args):
+ """ """
+ val = dict.pop(self, key, *args)
+ if key in self.scalars:
+ del self.comments[key]
+ del self.inline_comments[key]
+ self.scalars.remove(key)
+ elif key in self.sections:
+ del self.comments[key]
+ del self.inline_comments[key]
+ self.sections.remove(key)
+ if self.main.interpolation and isinstance(val, StringTypes):
+ return self._interpolate(key, val)
+ return val
+
+ def popitem(self):
+ """Pops the first (key,val)"""
+ sequence = (self.scalars + self.sections)
+ if not sequence:
+ raise KeyError, ": 'popitem(): dictionary is empty'"
+ key = sequence[0]
+ val = self[key]
+ del self[key]
+ return key, val
+
+ def clear(self):
+ """
+ A version of clear that also affects scalars/sections
+ Also clears comments and configspec.
+
+ Leaves other attributes alone :
+ depth/main/parent are not affected
+ """
+ dict.clear(self)
+ self.scalars = []
+ self.sections = []
+ self.comments = {}
+ self.inline_comments = {}
+ self.configspec = {}
+
+ def setdefault(self, key, default=None):
+ """A version of setdefault that sets sequence if appropriate."""
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return self[key]
+
+ def items(self):
+ """ """
+ return zip((self.scalars + self.sections), self.values())
+
+ def keys(self):
+ """ """
+ return (self.scalars + self.sections)
+
+ def values(self):
+ """ """
+ return [self[key] for key in (self.scalars + self.sections)]
+
+ def iteritems(self):
+ """ """
+ return iter(self.items())
+
+ def iterkeys(self):
+ """ """
+ return iter((self.scalars + self.sections))
+
+ __iter__ = iterkeys
+
+ def itervalues(self):
+ """ """
+ return iter(self.values())
+
+ def __repr__(self):
+ return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
+ for key in (self.scalars + self.sections)])
+
+ __str__ = __repr__
+
+ # Extra methods - not in a normal dictionary
+
+ def dict(self):
+ """
+ Return a deepcopy of self as a dictionary.
+
+ All members that are ``Section`` instances are recursively turned to
+ ordinary dictionaries - by calling their ``dict`` method.
+
+ >>> n = a.dict()
+ >>> n == a
+ 1
+ >>> n is a
+ 0
+ """
+ newdict = {}
+ for entry in self:
+ this_entry = self[entry]
+ if isinstance(this_entry, Section):
+ this_entry = this_entry.dict()
+ elif isinstance(this_entry, list):
+ # create a copy rather than a reference
+ this_entry = list(this_entry)
+ elif isinstance(this_entry, tuple):
+ # create a copy rather than a reference
+ this_entry = tuple(this_entry)
+ newdict[entry] = this_entry
+ return newdict
+
+ def merge(self, indict):
+ """
+ A recursive update - useful for merging config files.
+
+ >>> a = '''[section1]
+ ... option1 = True
+ ... [[subsection]]
+ ... more_options = False
+ ... # end of file'''.splitlines()
+ >>> b = '''# File is user.ini
+ ... [section1]
+ ... option1 = False
+ ... # end of file'''.splitlines()
+ >>> c1 = ConfigObj(b)
+ >>> c2 = ConfigObj(a)
+ >>> c2.merge(c1)
+ >>> c2
+ {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
+ """
+ for key, val in indict.items():
+ if (key in self and isinstance(self[key], dict) and
+ isinstance(val, dict)):
+ self[key].merge(val)
+ else:
+ self[key] = val
+
+ def rename(self, oldkey, newkey):
+ """
+ Change a keyname to another, without changing position in sequence.
+
+ Implemented so that transformations can be made on keys,
+ as well as on values. (used by encode and decode)
+
+ Also renames comments.
+ """
+ if oldkey in self.scalars:
+ the_list = self.scalars
+ elif oldkey in self.sections:
+ the_list = self.sections
+ else:
+ raise KeyError, 'Key "%s" not found.' % oldkey
+ pos = the_list.index(oldkey)
+ #
+ val = self[oldkey]
+ dict.__delitem__(self, oldkey)
+ dict.__setitem__(self, newkey, val)
+ the_list.remove(oldkey)
+ the_list.insert(pos, newkey)
+ comm = self.comments[oldkey]
+ inline_comment = self.inline_comments[oldkey]
+ del self.comments[oldkey]
+ del self.inline_comments[oldkey]
+ self.comments[newkey] = comm
+ self.inline_comments[newkey] = inline_comment
+
+ def walk(self, function, raise_errors=True,
+ call_on_sections=False, **keywargs):
+ """
+ Walk every member and call a function on the keyword and value.
+
+ Return a dictionary of the return values
+
+ If the function raises an exception, raise the errror
+ unless ``raise_errors=False``, in which case set the return value to
+ ``False``.
+
+ Any unrecognised keyword arguments you pass to walk, will be pased on
+ to the function you pass in.
+
+ Note: if ``call_on_sections`` is ``True`` then - on encountering a
+ subsection, *first* the function is called for the *whole* subsection,
+ and then recurses into it's members. This means your function must be
+ able to handle strings, dictionaries and lists. This allows you
+ to change the key of subsections as well as for ordinary members. The
+ return value when called on the whole subsection has to be discarded.
+
+ See the encode and decode methods for examples, including functions.
+
+ .. caution::
+
+ You can use ``walk`` to transform the names of members of a section
+ but you mustn't add or delete members.
+
+ >>> config = '''[XXXXsection]
+ ... XXXXkey = XXXXvalue'''.splitlines()
+ >>> cfg = ConfigObj(config)
+ >>> cfg
+ {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
+ >>> def transform(section, key):
+ ... val = section[key]
+ ... newkey = key.replace('XXXX', 'CLIENT1')
+ ... section.rename(key, newkey)
+ ... if isinstance(val, (tuple, list, dict)):
+ ... pass
+ ... else:
+ ... val = val.replace('XXXX', 'CLIENT1')
+ ... section[newkey] = val
+ >>> cfg.walk(transform, call_on_sections=True)
+ {'CLIENT1section': {'CLIENT1key': None}}
+ >>> cfg
+ {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
+ """
+ out = {}
+ # scalars first
+ for i in range(len(self.scalars)):
+ entry = self.scalars[i]
+ try:
+ val = function(self, entry, **keywargs)
+ # bound again in case name has changed
+ entry = self.scalars[i]
+ out[entry] = val
+ except Exception:
+ if raise_errors:
+ raise
+ else:
+ entry = self.scalars[i]
+ out[entry] = False
+ # then sections
+ for i in range(len(self.sections)):
+ entry = self.sections[i]
+ if call_on_sections:
+ try:
+ function(self, entry, **keywargs)
+ except Exception:
+ if raise_errors:
+ raise
+ else:
+ entry = self.sections[i]
+ out[entry] = False
+ # bound again in case name has changed
+ entry = self.sections[i]
+ # previous result is discarded
+ out[entry] = self[entry].walk(
+ function,
+ raise_errors=raise_errors,
+ call_on_sections=call_on_sections,
+ **keywargs)
+ return out
+
+ def decode(self, encoding):
+ """
+ Decode all strings and values to unicode, using the specified encoding.
+
+ Works with subsections and list values.
+
+ Uses the ``walk`` method.
+
+ Testing ``encode`` and ``decode``.
+ >>> m = ConfigObj(a)
+ >>> m.decode('ascii')
+ >>> def testuni(val):
+ ... for entry in val:
+ ... if not isinstance(entry, unicode):
+ ... print >> sys.stderr, type(entry)
+ ... raise AssertionError, 'decode failed.'
+ ... if isinstance(val[entry], dict):
+ ... testuni(val[entry])
+ ... elif not isinstance(val[entry], unicode):
+ ... raise AssertionError, 'decode failed.'
+ >>> testuni(m)
+ >>> m.encode('ascii')
+ >>> a == m
+ 1
+ """
+ warn('use of ``decode`` is deprecated.', DeprecationWarning)
+ def decode(section, key, encoding=encoding, warn=True):
+ """ """
+ val = section[key]
+ if isinstance(val, (list, tuple)):
+ newval = []
+ for entry in val:
+ newval.append(entry.decode(encoding))
+ elif isinstance(val, dict):
+ newval = val
+ else:
+ newval = val.decode(encoding)
+ newkey = key.decode(encoding)
+ section.rename(key, newkey)
+ section[newkey] = newval
+ # using ``call_on_sections`` allows us to modify section names
+ self.walk(decode, call_on_sections=True)
+
+ def encode(self, encoding):
+ """
+ Encode all strings and values from unicode,
+ using the specified encoding.
+
+ Works with subsections and list values.
+ Uses the ``walk`` method.
+ """
+ warn('use of ``encode`` is deprecated.', DeprecationWarning)
+ def encode(section, key, encoding=encoding):
+ """ """
+ val = section[key]
+ if isinstance(val, (list, tuple)):
+ newval = []
+ for entry in val:
+ newval.append(entry.encode(encoding))
+ elif isinstance(val, dict):
+ newval = val
+ else:
+ newval = val.encode(encoding)
+ newkey = key.encode(encoding)
+ section.rename(key, newkey)
+ section[newkey] = newval
+ self.walk(encode, call_on_sections=True)
+
+ def istrue(self, key):
+ """A deprecated version of ``as_bool``."""
+ warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
+ 'instead.', DeprecationWarning)
+ return self.as_bool(key)
+
+ def as_bool(self, key):
+ """
+ Accepts a key as input. The corresponding value must be a string or
+ the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
+ retain compatibility with Python 2.2.
+
+ If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
+ ``True``.
+
+ If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
+ ``False``.
+
+ ``as_bool`` is not case sensitive.
+
+ Any other input will raise a ``ValueError``.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_bool('a')
+ Traceback (most recent call last):
+ ValueError: Value "fish" is neither True nor False
+ >>> a['b'] = 'True'
+ >>> a.as_bool('b')
+ 1
+ >>> a['b'] = 'off'
+ >>> a.as_bool('b')
+ 0
+ """
+ val = self[key]
+ if val == True:
+ return True
+ elif val == False:
+ return False
+ else:
+ try:
+ if not isinstance(val, StringTypes):
+ raise KeyError
+ else:
+ return self.main._bools[val.lower()]
+ except KeyError:
+ raise ValueError('Value "%s" is neither True nor False' % val)
+
+ def as_int(self, key):
+ """
+ A convenience method which coerces the specified value to an integer.
+
+ If the value is an invalid literal for ``int``, a ``ValueError`` will
+ be raised.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_int('a')
+ Traceback (most recent call last):
+ ValueError: invalid literal for int(): fish
+ >>> a['b'] = '1'
+ >>> a.as_int('b')
+ 1
+ >>> a['b'] = '3.2'
+ >>> a.as_int('b')
+ Traceback (most recent call last):
+ ValueError: invalid literal for int(): 3.2
+ """
+ return int(self[key])
+
+ def as_float(self, key):
+ """
+ A convenience method which coerces the specified value to a float.
+
+ If the value is an invalid literal for ``float``, a ``ValueError`` will
+ be raised.
+
+ >>> a = ConfigObj()
+ >>> a['a'] = 'fish'
+ >>> a.as_float('a')
+ Traceback (most recent call last):
+ ValueError: invalid literal for float(): fish
+ >>> a['b'] = '1'
+ >>> a.as_float('b')
+ 1.0
+ >>> a['b'] = '3.2'
+ >>> a.as_float('b')
+ 3.2000000000000002
+ """
+ return float(self[key])
+
+
+class ConfigObj(Section):
+ """An object to read, create, and write config files."""
+
+ _keyword = re.compile(r'''^ # line start
+ (\s*) # indentation
+ ( # keyword
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'"=].*?) # no quotes
+ )
+ \s*=\s* # divider
+ (.*) # value (including list values and comments)
+ $ # line end
+ ''',
+ re.VERBOSE)
+
+ _sectionmarker = re.compile(r'''^
+ (\s*) # 1: indentation
+ ((?:\[\s*)+) # 2: section marker open
+ ( # 3: section name open
+ (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
+ (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
+ (?:[^'"\s].*?) # at least one non-space unquoted
+ ) # section name close
+ ((?:\s*\])+) # 4: section marker close
+ \s*(\#.*)? # 5: optional comment
+ $''',
+ re.VERBOSE)
+
+ # this regexp pulls list values out as a single string
+ # or single values and comments
+ # FIXME: this regex adds a '' to the end of comma terminated lists
+ # workaround in ``_handle_value``
+ _valueexp = re.compile(r'''^
+ (?:
+ (?:
+ (
+ (?:
+ (?:
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#][^,\#]*?) # unquoted
+ )
+ \s*,\s* # comma
+ )* # match all list items ending in a comma (if any)
+ )
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#\s][^,]*?)| # unquoted
+ (?:(?<!,)) # Empty value
+ )? # last item in a list - or string value
+ )|
+ (,) # alternatively a single comma - empty list
+ )
+ \s*(\#.*)? # optional comment
+ $''',
+ re.VERBOSE)
+
+ # use findall to get the members of a list value
+ _listvalueexp = re.compile(r'''
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'",\#].*?) # unquoted
+ )
+ \s*,\s* # comma
+ ''',
+ re.VERBOSE)
+
+ # this regexp is used for the value
+ # when lists are switched off
+ _nolistvalue = re.compile(r'''^
+ (
+ (?:".*?")| # double quotes
+ (?:'.*?')| # single quotes
+ (?:[^'"\#].*?)| # unquoted
+ (?:) # Empty value
+ )
+ \s*(\#.*)? # optional comment
+ $''',
+ re.VERBOSE)
+
+ # regexes for finding triple quoted values on one line
+ _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
+ _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
+ _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
+ _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
+
+ _triple_quote = {
+ "'''": (_single_line_single, _multi_line_single),
+ '"""': (_single_line_double, _multi_line_double),
+ }
+
+ # Used by the ``istrue`` Section method
+ _bools = {
+ 'yes': True, 'no': False,
+ 'on': True, 'off': False,
+ '1': True, '0': False,
+ 'true': True, 'false': False,
+ }
+
+ def __init__(self, infile=None, options=None, **kwargs):
+ """
+ Parse or create a config file object.
+
+ ``ConfigObj(infile=None, options=None, **kwargs)``
+ """
+ if infile is None:
+ infile = []
+ if options is None:
+ options = {}
+ else:
+ options = dict(options)
+ # keyword arguments take precedence over an options dictionary
+ options.update(kwargs)
+ # init the superclass
+ Section.__init__(self, self, 0, self)
+ #
+ defaults = OPTION_DEFAULTS.copy()
+ for entry in options.keys():
+ if entry not in defaults.keys():
+ raise TypeError, 'Unrecognised option "%s".' % entry
+ # TODO: check the values too.
+ #
+ # Add any explicit options to the defaults
+ defaults.update(options)
+ #
+ # initialise a few variables
+ self.filename = None
+ self._errors = []
+ self.raise_errors = defaults['raise_errors']
+ self.interpolation = defaults['interpolation']
+ self.list_values = defaults['list_values']
+ self.create_empty = defaults['create_empty']
+ self.file_error = defaults['file_error']
+ self.stringify = defaults['stringify']
+ self.indent_type = defaults['indent_type']
+ self.encoding = defaults['encoding']
+ self.default_encoding = defaults['default_encoding']
+ self.BOM = False
+ self.newlines = None
+ self.write_empty_values = defaults['write_empty_values']
+ self.unrepr = defaults['unrepr']
+ #
+ self.initial_comment = []
+ self.final_comment = []
+ #
+ self._terminated = False
+ #
+ if isinstance(infile, StringTypes):
+ self.filename = infile
+ if os.path.isfile(infile):
+ infile = open(infile).read() or []
+ elif self.file_error:
+ # raise an error if the file doesn't exist
+ raise IOError, 'Config file not found: "%s".' % self.filename
+ else:
+ # file doesn't already exist
+ if self.create_empty:
+ # this is a good test that the filename specified
+ # isn't impossible - like on a non existent device
+ h = open(infile, 'w')
+ h.write('')
+ h.close()
+ infile = []
+ elif isinstance(infile, (list, tuple)):
+ infile = list(infile)
+ elif isinstance(infile, dict):
+ # initialise self
+ # the Section class handles creating subsections
+ if isinstance(infile, ConfigObj):
+ # get a copy of our ConfigObj
+ infile = infile.dict()
+ for entry in infile:
+ self[entry] = infile[entry]
+ del self._errors
+ if defaults['configspec'] is not None:
+ self._handle_configspec(defaults['configspec'])
+ else:
+ self.configspec = None
+ return
+ elif hasattr(infile, 'read'):
+ # This supports file like objects
+ infile = infile.read() or []
+ # needs splitting into lines - but needs doing *after* decoding
+ # in case it's not an 8 bit encoding
+ else:
+ raise TypeError, ('infile must be a filename,'
+ ' file like object, or list of lines.')
+ #
+ if infile:
+ # don't do it for the empty ConfigObj
+ infile = self._handle_bom(infile)
+ # infile is now *always* a list
+ #
+ # Set the newlines attribute (first line ending it finds)
+ # and strip trailing '\n' or '\r' from lines
+ for line in infile:
+ if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
+ continue
+ for end in ('\r\n', '\n', '\r'):
+ if line.endswith(end):
+ self.newlines = end
+ break
+ break
+ if infile[-1] and infile[-1] in ('\r', '\n', '\r\n'):
+ self._terminated = True
+ infile = [line.rstrip('\r\n') for line in infile]
+ #
+ self._parse(infile)
+ # if we had any errors, now is the time to raise them
+ if self._errors:
+ info = "at line %s." % self._errors[0].line_number
+ if len(self._errors) > 1:
+ msg = ("Parsing failed with several errors.\nFirst error %s" %
+ info)
+ error = ConfigObjError(msg)
+ else:
+ error = self._errors[0]
+ # set the errors attribute; it's a list of tuples:
+ # (error_type, message, line_number)
+ error.errors = self._errors
+ # set the config attribute
+ error.config = self
+ raise error
+ # delete private attributes
+ del self._errors
+ #
+ if defaults['configspec'] is None:
+ self.configspec = None
+ else:
+ self._handle_configspec(defaults['configspec'])
+
+ def __repr__(self):
+ return 'ConfigObj({%s})' % ', '.join(
+ [('%s: %s' % (repr(key), repr(self[key]))) for key in
+ (self.scalars + self.sections)])
+
+ def _handle_bom(self, infile):
+ """
+ Handle any BOM, and decode if necessary.
+
+ If an encoding is specified, that *must* be used - but the BOM should
+ still be removed (and the BOM attribute set).
+
+ (If the encoding is wrongly specified, then a BOM for an alternative
+ encoding won't be discovered or removed.)
+
+ If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
+ removed. The BOM attribute will be set. UTF16 will be decoded to
+ unicode.
+
+ NOTE: This method must not be called with an empty ``infile``.
+
+ Specifying the *wrong* encoding is likely to cause a
+ ``UnicodeDecodeError``.
+
+ ``infile`` must always be returned as a list of lines, but may be
+ passed in as a single string.
+ """
+ if ((self.encoding is not None) and
+ (self.encoding.lower() not in BOM_LIST)):
+ # No need to check for a BOM
+ # the encoding specified doesn't have one
+ # just decode
+ return self._decode(infile, self.encoding)
+ #
+ if isinstance(infile, (list, tuple)):
+ line = infile[0]
+ else:
+ line = infile
+ if self.encoding is not None:
+ # encoding explicitly supplied
+ # And it could have an associated BOM
+ # TODO: if encoding is just UTF16 - we ought to check for both
+ # TODO: big endian and little endian versions.
+ enc = BOM_LIST[self.encoding.lower()]
+ if enc == 'utf_16':
+ # For UTF16 we try big endian and little endian
+ for BOM, (encoding, final_encoding) in BOMS.items():
+ if not final_encoding:
+ # skip UTF8
+ continue
+ if infile.startswith(BOM):
+ ### BOM discovered
+ ##self.BOM = True
+ # Don't need to remove BOM
+ return self._decode(infile, encoding)
+ #
+ # If we get this far, will *probably* raise a DecodeError
+ # As it doesn't appear to start with a BOM
+ return self._decode(infile, self.encoding)
+ #
+ # Must be UTF8
+ BOM = BOM_SET[enc]
+ if not line.startswith(BOM):
+ return self._decode(infile, self.encoding)
+ #
+ newline = line[len(BOM):]
+ #
+ # BOM removed
+ if isinstance(infile, (list, tuple)):
+ infile[0] = newline
+ else:
+ infile = newline
+ self.BOM = True
+ return self._decode(infile, self.encoding)
+ #
+ # No encoding specified - so we need to check for UTF8/UTF16
+ for BOM, (encoding, final_encoding) in BOMS.items():
+ if not line.startswith(BOM):
+ continue
+ else:
+ # BOM discovered
+ self.encoding = final_encoding
+ if not final_encoding:
+ self.BOM = True
+ # UTF8
+ # remove BOM
+ newline = line[len(BOM):]
+ if isinstance(infile, (list, tuple)):
+ infile[0] = newline
+ else:
+ infile = newline
+ # UTF8 - don't decode
+ if isinstance(infile, StringTypes):
+ return infile.splitlines(True)
+ else:
+ return infile
+ # UTF16 - have to decode
+ return self._decode(infile, encoding)
+ #
+ # No BOM discovered and no encoding specified, just return
+ if isinstance(infile, StringTypes):
+ # infile read from a file will be a single string
+ return infile.splitlines(True)
+ else:
+ return infile
+
+ def _a_to_u(self, aString):
+ """Decode ASCII strings to unicode if a self.encoding is specified."""
+ if self.encoding:
+ return aString.decode('ascii')
+ else:
+ return aString
+
+ def _decode(self, infile, encoding):
+ """
+ Decode infile to unicode. Using the specified encoding.
+
+ if is a string, it also needs converting to a list.
+ """
+ if isinstance(infile, StringTypes):
+ # can't be unicode
+ # NOTE: Could raise a ``UnicodeDecodeError``
+ return infile.decode(encoding).splitlines(True)
+ for i, line in enumerate(infile):
+ if not isinstance(line, unicode):
+ # NOTE: The isinstance test here handles mixed lists of unicode/string
+ # NOTE: But the decode will break on any non-string values
+ # NOTE: Or could raise a ``UnicodeDecodeError``
+ infile[i] = line.decode(encoding)
+ return infile
+
+ def _decode_element(self, line):
+ """Decode element to unicode if necessary."""
+ if not self.encoding:
+ return line
+ if isinstance(line, str) and self.default_encoding:
+ return line.decode(self.default_encoding)
+ return line
+
+ def _str(self, value):
+ """
+ Used by ``stringify`` within validate, to turn non-string values
+ into strings.
+ """
+ if not isinstance(value, StringTypes):
+ return str(value)
+ else:
+ return value
+
+ def _parse(self, infile):
+ """Actually parse the config file."""
+ temp_list_values = self.list_values
+ if self.unrepr:
+ self.list_values = False
+ comment_list = []
+ done_start = False
+ this_section = self
+ maxline = len(infile) - 1
+ cur_index = -1
+ reset_comment = False
+ while cur_index < maxline:
+ if reset_comment:
+ comment_list = []
+ cur_index += 1
+ line = infile[cur_index]
+ sline = line.strip()
+ # do we have anything on the line ?
+ if not sline or sline.startswith('#') or sline.startswith(';'):
+ reset_comment = False
+ comment_list.append(line)
+ continue
+ if not done_start:
+ # preserve initial comment
+ self.initial_comment = comment_list
+ comment_list = []
+ done_start = True
+ reset_comment = True
+ # first we check if it's a section marker
+ mat = self._sectionmarker.match(line)
+ if mat is not None:
+ # is a section line
+ (indent, sect_open, sect_name, sect_close, comment) = (
+ mat.groups())
+ if indent and (self.indent_type is None):
+ self.indent_type = indent
+ cur_depth = sect_open.count('[')
+ if cur_depth != sect_close.count(']'):
+ self._handle_error(
+ "Cannot compute the section depth at line %s.",
+ NestingError, infile, cur_index)
+ continue
+ #
+ if cur_depth < this_section.depth:
+ # the new section is dropping back to a previous level
+ try:
+ parent = self._match_depth(
+ this_section,
+ cur_depth).parent
+ except SyntaxError:
+ self._handle_error(
+ "Cannot compute nesting level at line %s.",
+ NestingError, infile, cur_index)
+ continue
+ elif cur_depth == this_section.depth:
+ # the new section is a sibling of the current section
+ parent = this_section.parent
+ elif cur_depth == this_section.depth + 1:
+ # the new section is a child the current section
+ parent = this_section
+ else:
+ self._handle_error(
+ "Section too nested at line %s.",
+ NestingError, infile, cur_index)
+ #
+ sect_name = self._unquote(sect_name)
+ if parent.has_key(sect_name):
+ self._handle_error(
+ 'Duplicate section name at line %s.',
+ DuplicateError, infile, cur_index)
+ continue
+ # create the new section
+ this_section = Section(
+ parent,
+ cur_depth,
+ self,
+ name=sect_name)
+ parent[sect_name] = this_section
+ parent.inline_comments[sect_name] = comment
+ parent.comments[sect_name] = comment_list
+ continue
+ #
+ # it's not a section marker,
+ # so it should be a valid ``key = value`` line
+ mat = self._keyword.match(line)
+ if mat is None:
+ # it neither matched as a keyword
+ # or a section marker
+ self._handle_error(
+ 'Invalid line at line "%s".',
+ ParseError, infile, cur_index)
+ else:
+ # is a keyword value
+ # value will include any inline comment
+ (indent, key, value) = mat.groups()
+ if indent and (self.indent_type is None):
+ self.indent_type = indent
+ # check for a multiline value
+ if value[:3] in ['"""', "'''"]:
+ try:
+ (value, comment, cur_index) = self._multiline(
+ value, infile, cur_index, maxline)
+ except SyntaxError:
+ self._handle_error(
+ 'Parse error in value at line %s.',
+ ParseError, infile, cur_index)
+ continue
+ else:
+ if self.unrepr:
+ comment = ''
+ try:
+ value = unrepr(value)
+ except Exception, e:
+ if type(e) == UnknownType:
+ msg = 'Unknown name or type in value at line %s.'
+ else:
+ msg = 'Parse error in value at line %s.'
+ self._handle_error(msg, UnreprError, infile,
+ cur_index)
+ continue
+ else:
+ if self.unrepr:
+ comment = ''
+ try:
+ value = unrepr(value)
+ except Exception, e:
+ if isinstance(e, UnknownType):
+ msg = 'Unknown name or type in value at line %s.'
+ else:
+ msg = 'Parse error in value at line %s.'
+ self._handle_error(msg, UnreprError, infile,
+ cur_index)
+ continue
+ else:
+ # extract comment and lists
+ try:
+ (value, comment) = self._handle_value(value)
+ except SyntaxError:
+ self._handle_error(
+ 'Parse error in value at line %s.',
+ ParseError, infile, cur_index)
+ continue
+ #
+ key = self._unquote(key)
+ if this_section.has_key(key):
+ self._handle_error(
+ 'Duplicate keyword name at line %s.',
+ DuplicateError, infile, cur_index)
+ continue
+ # add the key.
+ # we set unrepr because if we have got this far we will never
+ # be creating a new section
+ this_section.__setitem__(key, value, unrepr=True)
+ this_section.inline_comments[key] = comment
+ this_section.comments[key] = comment_list
+ continue
+ #
+ if self.indent_type is None:
+ # no indentation used, set the type accordingly
+ self.indent_type = ''
+ #
+ if self._terminated:
+ comment_list.append('')
+ # preserve the final comment
+ if not self and not self.initial_comment:
+ self.initial_comment = comment_list
+ elif not reset_comment:
+ self.final_comment = comment_list
+ self.list_values = temp_list_values
+
+ def _match_depth(self, sect, depth):
+ """
+ Given a section and a depth level, walk back through the sections
+ parents to see if the depth level matches a previous section.
+
+ Return a reference to the right section,
+ or raise a SyntaxError.
+ """
+ while depth < sect.depth:
+ if sect is sect.parent:
+ # we've reached the top level already
+ raise SyntaxError
+ sect = sect.parent
+ if sect.depth == depth:
+ return sect
+ # shouldn't get here
+ raise SyntaxError
+
+ def _handle_error(self, text, ErrorClass, infile, cur_index):
+ """
+ Handle an error according to the error settings.
+
+ Either raise the error or store it.
+ The error will have occured at ``cur_index``
+ """
+ line = infile[cur_index]
+ cur_index += 1
+ message = text % cur_index
+ error = ErrorClass(message, cur_index, line)
+ if self.raise_errors:
+ # raise the error - parsing stops here
+ raise error
+ # store the error
+ # reraise when parsing has finished
+ self._errors.append(error)
+
+ def _unquote(self, value):
+ """Return an unquoted version of a value"""
+ if (value[0] == value[-1]) and (value[0] in ('"', "'")):
+ value = value[1:-1]
+ return value
+
+ def _quote(self, value, multiline=True):
+ """
+ Return a safely quoted version of a value.
+
+ Raise a ConfigObjError if the value cannot be safely quoted.
+ If multiline is ``True`` (default) then use triple quotes
+ if necessary.
+
+ Don't quote values that don't need it.
+ Recursively quote members of a list and return a comma joined list.
+ Multiline is ``False`` for lists.
+ Obey list syntax for empty and single member lists.
+
+ If ``list_values=False`` then the value is only quoted if it contains
+ a ``\n`` (is multiline).
+
+ If ``write_empty_values`` is set, and the value is an empty string, it
+ won't be quoted.
+ """
+ if multiline and self.write_empty_values and value == '':
+ # Only if multiline is set, so that it is used for values not
+ # keys, and not values that are part of a list
+ return ''
+ if multiline and isinstance(value, (list, tuple)):
+ if not value:
+ return ','
+ elif len(value) == 1:
+ return self._quote(value[0], multiline=False) + ','
+ return ', '.join([self._quote(val, multiline=False)
+ for val in value])
+ if not isinstance(value, StringTypes):
+ if self.stringify:
+ value = str(value)
+ else:
+ raise TypeError, 'Value "%s" is not a string.' % value
+ squot = "'%s'"
+ dquot = '"%s"'
+ noquot = "%s"
+ wspace_plus = ' \r\t\n\v\t\'"'
+ tsquot = '"""%s"""'
+ tdquot = "'''%s'''"
+ if not value:
+ return '""'
+ if (not self.list_values and '\n' not in value) or not (multiline and
+ ((("'" in value) and ('"' in value)) or ('\n' in value))):
+ if not self.list_values:
+ # we don't quote if ``list_values=False``
+ quot = noquot
+ # for normal values either single or double quotes will do
+ elif '\n' in value:
+ # will only happen if multiline is off - e.g. '\n' in key
+ raise ConfigObjError, ('Value "%s" cannot be safely quoted.' %
+ value)
+ elif ((value[0] not in wspace_plus) and
+ (value[-1] not in wspace_plus) and
+ (',' not in value)):
+ quot = noquot
+ else:
+ if ("'" in value) and ('"' in value):
+ raise ConfigObjError, (
+ 'Value "%s" cannot be safely quoted.' % value)
+ elif '"' in value:
+ quot = squot
+ else:
+ quot = dquot
+ else:
+ # if value has '\n' or "'" *and* '"', it will need triple quotes
+ if (value.find('"""') != -1) and (value.find("'''") != -1):
+ raise ConfigObjError, (
+ 'Value "%s" cannot be safely quoted.' % value)
+ if value.find('"""') == -1:
+ quot = tdquot
+ else:
+ quot = tsquot
+ return quot % value
+
+ def _handle_value(self, value):
+ """
+ Given a value string, unquote, remove comment,
+ handle lists. (including empty and single member lists)
+ """
+ # do we look for lists in values ?
+ if not self.list_values:
+ mat = self._nolistvalue.match(value)
+ if mat is None:
+ raise SyntaxError
+ # NOTE: we don't unquote here
+ return mat.groups()
+ #
+ mat = self._valueexp.match(value)
+ if mat is None:
+ # the value is badly constructed, probably badly quoted,
+ # or an invalid list
+ raise SyntaxError
+ (list_values, single, empty_list, comment) = mat.groups()
+ if (list_values == '') and (single is None):
+ # change this if you want to accept empty values
+ raise SyntaxError
+ # NOTE: note there is no error handling from here if the regex
+ # is wrong: then incorrect values will slip through
+ if empty_list is not None:
+ # the single comma - meaning an empty list
+ return ([], comment)
+ if single is not None:
+ # handle empty values
+ if list_values and not single:
+ # FIXME: the '' is a workaround because our regex now matches
+ # '' at the end of a list if it has a trailing comma
+ single = None
+ else:
+ single = single or '""'
+ single = self._unquote(single)
+ if list_values == '':
+ # not a list value
+ return (single, comment)
+ the_list = self._listvalueexp.findall(list_values)
+ the_list = [self._unquote(val) for val in the_list]
+ if single is not None:
+ the_list += [single]
+ return (the_list, comment)
+
+ def _multiline(self, value, infile, cur_index, maxline):
+ """Extract the value, where we are in a multiline situation."""
+ quot = value[:3]
+ newvalue = value[3:]
+ single_line = self._triple_quote[quot][0]
+ multi_line = self._triple_quote[quot][1]
+ mat = single_line.match(value)
+ if mat is not None:
+ retval = list(mat.groups())
+ retval.append(cur_index)
+ return retval
+ elif newvalue.find(quot) != -1:
+ # somehow the triple quote is missing
+ raise SyntaxError
+ #
+ while cur_index < maxline:
+ cur_index += 1
+ newvalue += '\n'
+ line = infile[cur_index]
+ if line.find(quot) == -1:
+ newvalue += line
+ else:
+ # end of multiline, process it
+ break
+ else:
+ # we've got to the end of the config, oops...
+ raise SyntaxError
+ mat = multi_line.match(line)
+ if mat is None:
+ # a badly formed line
+ raise SyntaxError
+ (value, comment) = mat.groups()
+ return (newvalue + value, comment, cur_index)
+
+ def _handle_configspec(self, configspec):
+ """Parse the configspec."""
+ # FIXME: Should we check that the configspec was created with the
+ # correct settings ? (i.e. ``list_values=False``)
+ if not isinstance(configspec, ConfigObj):
+ try:
+ configspec = ConfigObj(
+ configspec,
+ raise_errors=True,
+ file_error=True,
+ list_values=False)
+ except ConfigObjError, e:
+ # FIXME: Should these errors have a reference
+ # to the already parsed ConfigObj ?
+ raise ConfigspecError('Parsing configspec failed: %s' % e)
+ except IOError, e:
+ raise IOError('Reading configspec failed: %s' % e)
+ self._set_configspec_value(configspec, self)
+
+ def _set_configspec_value(self, configspec, section):
+ """Used to recursively set configspec values."""
+ if '__many__' in configspec.sections:
+ section.configspec['__many__'] = configspec['__many__']
+ if len(configspec.sections) > 1:
+ # FIXME: can we supply any useful information here ?
+ raise RepeatSectionError
+ if hasattr(configspec, 'initial_comment'):
+ section._configspec_initial_comment = configspec.initial_comment
+ section._configspec_final_comment = configspec.final_comment
+ section._configspec_encoding = configspec.encoding
+ section._configspec_BOM = configspec.BOM
+ section._configspec_newlines = configspec.newlines
+ section._configspec_indent_type = configspec.indent_type
+ for entry in configspec.scalars:
+ section._configspec_comments[entry] = configspec.comments[entry]
+ section._configspec_inline_comments[entry] = (
+ configspec.inline_comments[entry])
+ section.configspec[entry] = configspec[entry]
+ section._order.append(entry)
+ for entry in configspec.sections:
+ if entry == '__many__':
+ continue
+ section._cs_section_comments[entry] = configspec.comments[entry]
+ section._cs_section_inline_comments[entry] = (
+ configspec.inline_comments[entry])
+ if not section.has_key(entry):
+ section[entry] = {}
+ self._set_configspec_value(configspec[entry], section[entry])
+
+ def _handle_repeat(self, section, configspec):
+ """Dynamically assign configspec for repeated section."""
+ try:
+ section_keys = configspec.sections
+ scalar_keys = configspec.scalars
+ except AttributeError:
+ section_keys = [entry for entry in configspec
+ if isinstance(configspec[entry], dict)]
+ scalar_keys = [entry for entry in configspec
+ if not isinstance(configspec[entry], dict)]
+ if '__many__' in section_keys and len(section_keys) > 1:
+ # FIXME: can we supply any useful information here ?
+ raise RepeatSectionError
+ scalars = {}
+ sections = {}
+ for entry in scalar_keys:
+ val = configspec[entry]
+ scalars[entry] = val
+ for entry in section_keys:
+ val = configspec[entry]
+ if entry == '__many__':
+ scalars[entry] = val
+ continue
+ sections[entry] = val
+ #
+ section.configspec = scalars
+ for entry in sections:
+ if not section.has_key(entry):
+ section[entry] = {}
+ self._handle_repeat(section[entry], sections[entry])
+
+ def _write_line(self, indent_string, entry, this_entry, comment):
+ """Write an individual line, for the write method"""
+ # NOTE: the calls to self._quote here handles non-StringType values.
+ if not self.unrepr:
+ val = self._decode_element(self._quote(this_entry))
+ else:
+ val = repr(this_entry)
+ return '%s%s%s%s%s' % (
+ indent_string,
+ self._decode_element(self._quote(entry, multiline=False)),
+ self._a_to_u(' = '),
+ val,
+ self._decode_element(comment))
+
+ def _write_marker(self, indent_string, depth, entry, comment):
+ """Write a section marker line"""
+ return '%s%s%s%s%s' % (
+ indent_string,
+ self._a_to_u('[' * depth),
+ self._quote(self._decode_element(entry), multiline=False),
+ self._a_to_u(']' * depth),
+ self._decode_element(comment))
+
+ def _handle_comment(self, comment):
+ """Deal with a comment."""
+ if not comment:
+ return ''
+ start = self.indent_type
+ if not comment.startswith('#'):
+ start += self._a_to_u(' # ')
+ return (start + comment)
+
+ # Public methods
+
+ def write(self, outfile=None, section=None):
+ """
+ Write the current ConfigObj as a file
+
+ tekNico: FIXME: use StringIO instead of real files
+
+ >>> filename = a.filename
+ >>> a.filename = 'test.ini'
+ >>> a.write()
+ >>> a.filename = filename
+ >>> a == ConfigObj('test.ini', raise_errors=True)
+ 1
+ """
+ if self.indent_type is None:
+ # this can be true if initialised from a dictionary
+ self.indent_type = DEFAULT_INDENT_TYPE
+ #
+ out = []
+ cs = self._a_to_u('#')
+ csp = self._a_to_u('# ')
+ if section is None:
+ int_val = self.interpolation
+ self.interpolation = False
+ section = self
+ for line in self.initial_comment:
+ line = self._decode_element(line)
+ stripped_line = line.strip()
+ if stripped_line and not stripped_line.startswith(cs):
+ line = csp + line
+ out.append(line)
+ #
+ indent_string = self.indent_type * section.depth
+ for entry in (section.scalars + section.sections):
+ if entry in section.defaults:
+ # don't write out default values
+ continue
+ for comment_line in section.comments[entry]:
+ comment_line = self._decode_element(comment_line.lstrip())
+ if comment_line and not comment_line.startswith(cs):
+ comment_line = csp + comment_line
+ out.append(indent_string + comment_line)
+ this_entry = section[entry]
+ comment = self._handle_comment(section.inline_comments[entry])
+ #
+ if isinstance(this_entry, dict):
+ # a section
+ out.append(self._write_marker(
+ indent_string,
+ this_entry.depth,
+ entry,
+ comment))
+ out.extend(self.write(section=this_entry))
+ else:
+ out.append(self._write_line(
+ indent_string,
+ entry,
+ this_entry,
+ comment))
+ #
+ if section is self:
+ for line in self.final_comment:
+ line = self._decode_element(line)
+ stripped_line = line.strip()
+ if stripped_line and not stripped_line.startswith(cs):
+ line = csp + line
+ out.append(line)
+ self.interpolation = int_val
+ #
+ if section is not self:
+ return out
+ #
+ if (self.filename is None) and (outfile is None):
+ # output a list of lines
+ # might need to encode
+ # NOTE: This will *screw* UTF16, each line will start with the BOM
+ if self.encoding:
+ out = [l.encode(self.encoding) for l in out]
+ if (self.BOM and ((self.encoding is None) or
+ (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
+ # Add the UTF8 BOM
+ if not out:
+ out.append('')
+ out[0] = BOM_UTF8 + out[0]
+ return out
+ #
+ # Turn the list to a string, joined with correct newlines
+ output = (self._a_to_u(self.newlines or os.linesep)
+ ).join(out)
+ if self.encoding:
+ output = output.encode(self.encoding)
+ if (self.BOM and ((self.encoding is None) or
+ (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
+ # Add the UTF8 BOM
+ output = BOM_UTF8 + output
+ if outfile is not None:
+ outfile.write(output)
+ else:
+ h = open(self.filename, 'wb')
+ h.write(output)
+ h.close()
+
+ def validate(self, validator, preserve_errors=False, copy=False,
+ section=None):
+ """
+ Test the ConfigObj against a configspec.
+
+ It uses the ``validator`` object from *validate.py*.
+
+ To run ``validate`` on the current ConfigObj, call: ::
+
+ test = config.validate(validator)
+
+ (Normally having previously passed in the configspec when the ConfigObj
+ was created - you can dynamically assign a dictionary of checks to the
+ ``configspec`` attribute of a section though).
+
+ It returns ``True`` if everything passes, or a dictionary of
+ pass/fails (True/False). If every member of a subsection passes, it
+ will just have the value ``True``. (It also returns ``False`` if all
+ members fail).
+
+ In addition, it converts the values from strings to their native
+ types if their checks pass (and ``stringify`` is set).
+
+ If ``preserve_errors`` is ``True`` (``False`` is default) then instead
+ of a marking a fail with a ``False``, it will preserve the actual
+ exception object. This can contain info about the reason for failure.
+ For example the ``VdtValueTooSmallError`` indeicates that the value
+ supplied was too small. If a value (or section) is missing it will
+ still be marked as ``False``.
+
+ You must have the validate module to use ``preserve_errors=True``.
+
+ You can then use the ``flatten_errors`` function to turn your nested
+ results dictionary into a flattened list of failures - useful for
+ displaying meaningful error messages.
+ """
+ if section is None:
+ if self.configspec is None:
+ raise ValueError, 'No configspec supplied.'
+ if preserve_errors:
+ if VdtMissingValue is None:
+ raise ImportError('Missing validate module.')
+ section = self
+ #
+ spec_section = section.configspec
+ if copy and hasattr(section, '_configspec_initial_comment'):
+ section.initial_comment = section._configspec_initial_comment
+ section.final_comment = section._configspec_final_comment
+ section.encoding = section._configspec_encoding
+ section.BOM = section._configspec_BOM
+ section.newlines = section._configspec_newlines
+ section.indent_type = section._configspec_indent_type
+ if '__many__' in section.configspec:
+ many = spec_section['__many__']
+ # dynamically assign the configspecs
+ # for the sections below
+ for entry in section.sections:
+ self._handle_repeat(section[entry], many)
+ #
+ out = {}
+ ret_true = True
+ ret_false = True
+ order = [k for k in section._order if k in spec_section]
+ order += [k for k in spec_section if k not in order]
+ for entry in order:
+ if entry == '__many__':
+ continue
+ if (not entry in section.scalars) or (entry in section.defaults):
+ # missing entries
+ # or entries from defaults
+ missing = True
+ val = None
+ if copy and not entry in section.scalars:
+ # copy comments
+ section.comments[entry] = (
+ section._configspec_comments.get(entry, []))
+ section.inline_comments[entry] = (
+ section._configspec_inline_comments.get(entry, ''))
+ #
+ else:
+ missing = False
+ val = section[entry]
+ try:
+ check = validator.check(spec_section[entry],
+ val,
+ missing=missing
+ )
+ except validator.baseErrorClass, e:
+ if not preserve_errors or isinstance(e, VdtMissingValue):
+ out[entry] = False
+ else:
+ # preserve the error
+ out[entry] = e
+ ret_false = False
+ ret_true = False
+ else:
+ ret_false = False
+ out[entry] = True
+ if self.stringify or missing:
+ # if we are doing type conversion
+ # or the value is a supplied default
+ if not self.stringify:
+ if isinstance(check, (list, tuple)):
+ # preserve lists
+ check = [self._str(item) for item in check]
+ elif missing and check is None:
+ # convert the None from a default to a ''
+ check = ''
+ else:
+ check = self._str(check)
+ if (check != val) or missing:
+ section[entry] = check
+ if not copy and missing and entry not in section.defaults:
+ section.defaults.append(entry)
+ #
+ # Missing sections will have been created as empty ones when the
+ # configspec was read.
+ for entry in section.sections:
+ # FIXME: this means DEFAULT is not copied in copy mode
+ if section is self and entry == 'DEFAULT':
+ continue
+ if copy:
+ section.comments[entry] = section._cs_section_comments[entry]
+ section.inline_comments[entry] = (
+ section._cs_section_inline_comments[entry])
+ check = self.validate(validator, preserve_errors=preserve_errors,
+ copy=copy, section=section[entry])
+ out[entry] = check
+ if check == False:
+ ret_true = False
+ elif check == True:
+ ret_false = False
+ else:
+ ret_true = False
+ ret_false = False
+ #
+ if ret_true:
+ return True
+ elif ret_false:
+ return False
+ else:
+ return out
+
+class SimpleVal(object):
+ """
+ A simple validator.
+ Can be used to check that all members expected are present.
+
+ To use it, provide a configspec with all your members in (the value given
+ will be ignored). Pass an instance of ``SimpleVal`` to the ``validate``
+ method of your ``ConfigObj``. ``validate`` will return ``True`` if all
+ members are present, or a dictionary with True/False meaning
+ present/missing. (Whole missing sections will be replaced with ``False``)
+ """
+
+ def __init__(self):
+ self.baseErrorClass = ConfigObjError
+
+ def check(self, check, member, missing=False):
+ """A dummy check method, always returns the value unchanged."""
+ if missing:
+ raise self.baseErrorClass
+ return member
+
+# Check / processing functions for options
+def flatten_errors(cfg, res, levels=None, results=None):
+ """
+ An example function that will turn a nested dictionary of results
+ (as returned by ``ConfigObj.validate``) into a flat list.
+
+ ``cfg`` is the ConfigObj instance being checked, ``res`` is the results
+ dictionary returned by ``validate``.
+
+ (This is a recursive function, so you shouldn't use the ``levels`` or
+ ``results`` arguments - they are used by the function.
+
+ Returns a list of keys that failed. Each member of the list is a tuple :
+ ::
+
+ ([list of sections...], key, result)
+
+ If ``validate`` was called with ``preserve_errors=False`` (the default)
+ then ``result`` will always be ``False``.
+
+ *list of sections* is a flattened list of sections that the key was found
+ in.
+
+ If the section was missing then key will be ``None``.
+
+ If the value (or section) was missing then ``result`` will be ``False``.
+
+ If ``validate`` was called with ``preserve_errors=True`` and a value
+ was present, but failed the check, then ``result`` will be the exception
+ object returned. You can use this as a string that describes the failure.
+
+ For example *The value "3" is of the wrong type*.
+
+ >>> import validate
+ >>> vtor = validate.Validator()
+ >>> my_ini = '''
+ ... option1 = True
+ ... [section1]
+ ... option1 = True
+ ... [section2]
+ ... another_option = Probably
+ ... [section3]
+ ... another_option = True
+ ... [[section3b]]
+ ... value = 3
+ ... value2 = a
+ ... value3 = 11
+ ... '''
+ >>> my_cfg = '''
+ ... option1 = boolean()
+ ... option2 = boolean()
+ ... option3 = boolean(default=Bad_value)
+ ... [section1]
+ ... option1 = boolean()
+ ... option2 = boolean()
+ ... option3 = boolean(default=Bad_value)
+ ... [section2]
+ ... another_option = boolean()
+ ... [section3]
+ ... another_option = boolean()
+ ... [[section3b]]
+ ... value = integer
+ ... value2 = integer
+ ... value3 = integer(0, 10)
+ ... [[[section3b-sub]]]
+ ... value = string
+ ... [section4]
+ ... another_option = boolean()
+ ... '''
+ >>> cs = my_cfg.split('\\n')
+ >>> ini = my_ini.split('\\n')
+ >>> cfg = ConfigObj(ini, configspec=cs)
+ >>> res = cfg.validate(vtor, preserve_errors=True)
+ >>> errors = []
+ >>> for entry in flatten_errors(cfg, res):
+ ... section_list, key, error = entry
+ ... section_list.insert(0, '[root]')
+ ... if key is not None:
+ ... section_list.append(key)
+ ... else:
+ ... section_list.append('[missing]')
+ ... section_string = ', '.join(section_list)
+ ... errors.append((section_string, ' = ', error))
+ >>> errors.sort()
+ >>> for entry in errors:
+ ... print entry[0], entry[1], (entry[2] or 0)
+ [root], option2 = 0
+ [root], option3 = the value "Bad_value" is of the wrong type.
+ [root], section1, option2 = 0
+ [root], section1, option3 = the value "Bad_value" is of the wrong type.
+ [root], section2, another_option = the value "Probably" is of the wrong type.
+ [root], section3, section3b, section3b-sub, [missing] = 0
+ [root], section3, section3b, value2 = the value "a" is of the wrong type.
+ [root], section3, section3b, value3 = the value "11" is too big.
+ [root], section4, [missing] = 0
+ """
+ if levels is None:
+ # first time called
+ levels = []
+ results = []
+ if res is True:
+ return results
+ if res is False:
+ results.append((levels[:], None, False))
+ if levels:
+ levels.pop()
+ return results
+ for (key, val) in res.items():
+ if val == True:
+ continue
+ if isinstance(cfg.get(key), dict):
+ # Go down one level
+ levels.append(key)
+ flatten_errors(cfg[key], val, levels, results)
+ continue
+ results.append((levels[:], key, val))
+ #
+ # Go up one level
+ if levels:
+ levels.pop()
+ #
+ return results
+
+"""*A programming language is a medium of expression.* - Paul Graham"""
deleted file mode 100755
--- a/config/mozBDate.pm
+++ /dev/null
@@ -1,172 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998-2000
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# 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"),
-# 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 *****
-
-package mozBDate;
-
-use strict;
-use IO::File;
-
-BEGIN {
- use Exporter ();
- use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $milestone);
-
- $VERSION = 1.00;
- @ISA = qw(Exporter);
- @EXPORT = qw(&UpdateBuildNumber &SubstituteBuildNumber &SetMilestone);
- %EXPORT_TAGS = ( );
- @EXPORT_OK = qw();
-}
-
-local $mozBDate::milestone = "0.0";
-
-sub write_number($) {
- my ($file, $num) = @_;
- unlink($file);
- open(OUT, ">$file") || die "$file: $!\n";
- print OUT "$num\n";
- close(OUT);
-}
-
-sub UpdateBuildNumber($$) {
-
- my ($outfile, $official) = @_;
- my $given_date = $ENV{"MOZ_BUILD_DATE"};
- my $build_number;
-
- if ($given_date eq "") {
- # XP way of doing the build date.
- # 1998091509 = 1998, September, 15th, 9am local time zone
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
- localtime(time);
-
- # localtime returns year minus 1900
- $year = $year + 1900;
- $build_number = sprintf("%04d%02d%02d%02d", $year, 1+$mon,
- $mday, $hour);
- }
- else {
- $build_number = $given_date;
- }
-
- if ("$outfile" eq "") {
- print "$build_number\n";
- return;
- }
-
- if (!$official) {
- $build_number = "0000000000";
- }
-
- my $old_num = "";
-
- # Don't overwrite $outfile if its contents won't change
- if ( -e $outfile ) {
- open(OLD, "<$outfile") || die "$outfile: $!\n";
- $old_num = <OLD>;
- chomp($old_num);
- close(OLD);
- }
-
- if ($old_num ne $build_number) {
- &write_number($outfile, $build_number);
- }
- return;
-}
-
-sub SubstituteBuildNumber($$$) {
-
- my ($outfile, $build_num, $infile) = @_;
- my $INFILE = new IO::File;
- my $OUTFILE = new IO::File;
-
- open $INFILE, "<$build_num";
- my $build = <$INFILE>;
- close $INFILE;
- chomp $build;
- chop $build if (substr($build, -1, 1) eq "\r");
-
- if ($infile ne "") {
- open($INFILE, "< $infile") || die "$infile: $!\n";
- } else {
- open($INFILE, "< $outfile") || die "$outfile: $!\n";
- }
- open $OUTFILE, ">${outfile}.old" || die;
-
- while (<$INFILE>) {
- my $id = $_;
- my $temp;
- if ($id =~ "Build ID:") {
- $temp = "Build ID: " . $build;
- $id =~ s/Build ID:\s\d+/$temp/;
- print $OUTFILE $id;
- }
- elsif ($id =~ "NS_BUILD_ID") {
- $temp = "NS_BUILD_ID " . $build;
- $id =~ s/NS_BUILD_ID\s\d+/$temp/;
- print $OUTFILE $id;
- }
- elsif ($id =~ "GRE_BUILD_ID") {
- if (defined($ENV{'MOZ_MILESTONE_RELEASE'}) &&
- $ENV{'MOZ_MILESTONE_RELEASE'} ne "") {
- $temp = "GRE_BUILD_ID \"$milestone\"";
- } else {
- $temp = "GRE_BUILD_ID \"${milestone}_${build}\"";
- }
- $id =~ s/GRE_BUILD_ID\s\"\d+\"/$temp/;
- print $OUTFILE $id;
- }
- else {
- print $OUTFILE $_;
- }
- }
-
- close $INFILE;
- close $OUTFILE;
-
- unlink $outfile;
- rename "${outfile}.old", "$outfile";
-}
-
-sub SetMilestone($) {
- my ($mstone) = (@_);
- $milestone = $mstone if ($mstone ne "");
-}
-
-END {};
-
-1;
-
new file mode 100644
--- /dev/null
+++ b/config/printconfigsetting.py
@@ -0,0 +1,21 @@
+import configobj, sys
+
+try:
+ (file, section, key) = sys.argv[1:]
+except ValueError:
+ print "Usage: printconfigsetting.py <file> <section> <setting>"
+ sys.exit(1)
+
+c = configobj.ConfigObj(file)
+
+try:
+ s = c[section]
+except KeyError:
+ print >>sys.stderr, "Section [%s] not found." % section
+ sys.exit(1)
+
+try:
+ print s[key]
+except KeyError:
+ print >>sys.stderr, "Key %s not found." % key
+ sys.exit(1)
--- a/config/version_win.pl
+++ b/config/version_win.pl
@@ -133,17 +133,16 @@ if (!defined($module))
my $productversion = "0,0,0,0";
my $fileversion = $productversion;
my $fileos = "VOS__WINDOWS32";
if ($bits eq "16") { $fileos="VOS__WINDOWS16"; }
my $bufferstr=" ";
my $MILESTONE_FILE = "$topsrcdir/config/milestone.txt";
-my $BUILDID_FILE = "$depth/config/build_number";
#Read module.ver file
#Version file overrides for WIN32:
#WIN32_MODULE_COMMENT
#WIN32_MODULE_DESCRIPTION
#WIN32_MODULE_FILEVERSION
#WIN32_MODULE_COMPANYNAME
#WIN32_MODULE_FILEVERSION_STRING
@@ -238,27 +237,17 @@ if ($official eq "1") {
$fileflags = "0";
my @mstone = split(/\./,$milestone);
$mstone[1] =~s/\D*$//g;
$productversion="$mstone[0],$mstone[1],0,0";
}
- my ($buildid, $buildid_hi, $buildid_lo);
- open(NUMBER, "<$BUILDID_FILE") || die "No build number file\n";
- while ( <NUMBER> ) { $buildid = $_ }
- close (NUMBER);
- $buildid =~ s/^\s*(.*)\s*$/$1/;
- $buildid_hi = substr($buildid, 0, 5);
- $buildid_lo = substr($buildid, 5);
-
- $mfversion = $mpversion = "$milestone: $buildid";
- my @pvarray = split(',', $productversion);
- $fileversion = "$pvarray[0],$pvarray[1],$buildid_hi,$buildid_lo";
+ $mfversion = $mpversion = "$milestone";
}
my $copyright = "License: MPL 1.1/GPL 2.0/LGPL 2.1";
my $company = "Mozilla Foundation";
my $trademarks = "Mozilla";
my $productname = $displayname;
@@ -385,17 +374,16 @@ print RCFILE qq{
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
1 VERSIONINFO
- FILEVERSION $fileversion
PRODUCTVERSION $productversion
FILEFLAGSMASK 0x3fL
FILEFLAGS $fileflags
FILEOS $fileos
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -152,16 +152,17 @@
#include "nsGlobalWindowCommands.h"
#include "nsAutoPtr.h"
#include "nsContentUtils.h"
#include "nsCSSProps.h"
#include "nsIURIFixup.h"
#include "nsCDefaultURIFixup.h"
#include "nsEventDispatcher.h"
#include "nsIObserverService.h"
+#include "nsIXULAppInfo.h"
#include "nsNetUtil.h"
#include "plbase64.h"
#ifdef NS_PRINTING
#include "nsIPrintSettings.h"
#include "nsIPrintSettingsService.h"
#include "nsIWebBrowserPrint.h"
@@ -188,18 +189,16 @@
#define FORCE_PR_LOG 1
#endif
#include "prlog.h"
#ifdef PR_LOGGING
static PRLogModuleInfo* gDOMLeakPRLog;
#endif
-#include "nsBuildID.h"
-
nsIFactory *nsGlobalWindow::sComputedDOMStyleFactory = nsnull;
static nsIEntropyCollector *gEntropyCollector = nsnull;
static PRInt32 gRefCnt = 0;
static PRInt32 gOpenPopupSpamCount = 0;
static PopupControlState gPopupControlState = openAbused;
static PRInt32 gRunningTimeoutDepth = 0;
@@ -8245,18 +8244,28 @@ nsNavigator::GetOnLine(PRBool* aOnline)
*aOnline = !NS_IsOffline();
return NS_OK;
}
NS_IMETHODIMP
nsNavigator::GetBuildID(nsAString& aBuildID)
{
- aBuildID = NS_LITERAL_STRING(NS_STRINGIFY(NS_BUILD_ID));
-
+ nsCOMPtr<nsIXULAppInfo> appInfo =
+ do_GetService("@mozilla.org/xre/app-info;1");
+ if (!appInfo)
+ return NS_ERROR_NOT_IMPLEMENTED;
+
+ nsCAutoString buildID;
+ nsresult rv = appInfo->GetAppBuildID(buildID);
+ if (NS_FAILED(rv))
+ return rv;
+
+ aBuildID.Truncate();
+ AppendASCIItoUTF16(buildID, aBuildID);
return NS_OK;
}
NS_IMETHODIMP
nsNavigator::JavaEnabled(PRBool *aReturn)
{
nsresult rv = NS_OK;
*aReturn = PR_FALSE;
--- a/gfx/src/ps/nsPostScriptObj.cpp
+++ b/gfx/src/ps/nsPostScriptObj.cpp
@@ -68,20 +68,16 @@
#include "nsReadableUtils.h"
#include "nsICharsetAlias.h"
#include "nsNetUtil.h"
#include "nsIPersistentProperties2.h"
#include "nsCRT.h"
#include "nsFontMetricsPS.h"
-#ifndef NS_BUILD_ID
-#include "nsBuildID.h"
-#endif /* !NS_BUILD_ID */
-
#include "nsPrintfCString.h"
#include "prenv.h"
#include "prprf.h"
#include "prerror.h"
#include <errno.h>
#include <sys/wait.h>
@@ -408,18 +404,18 @@ nsPostScriptObj::write_prolog(FILE *aHan
fprintf(f, "%%!PS-Adobe-3.0\n");
fprintf(f, "%%%%BoundingBox: 0 0 %s %s\n",
fpCString(NSToCoordRound(fWidth)).get(),
fpCString(NSToCoordRound(fHeight)).get());
fprintf(f, "%%%%HiResBoundingBox: 0 0 %s %s\n",
fpCString(fWidth).get(),
fpCString(fHeight).get());
- fprintf(f, "%%%%Creator: Mozilla PostScript module (%s/%lu)\n",
- "rv:" MOZILLA_VERSION, (unsigned long)NS_BUILD_ID);
+ fprintf(f, "%%%%Creator: Mozilla PostScript module (%s)\n",
+ "rv:" MOZILLA_VERSION);
fprintf(f, "%%%%DocumentData: Clean8Bit\n");
fprintf(f, "%%%%DocumentPaperSizes: %s\n", mPrintSetup->paper_name);
fprintf(f, "%%%%Orientation: %s\n",
mPrintContext->prSetup->landscape ? "Landscape" : "Portrait");
fprintf(f, "%%%%Pages: %d\n", (int) mPageNumber - 1);
fprintf(f, "%%%%PageOrder: %s\n",
mPrintContext->prSetup->reverse ? "Descend" : "Ascend");
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -45,19 +45,16 @@ include $(DEPTH)/config/autoconf.mk
# Solaris and Tru64 UNIX sh blows
ifeq ($(OS_ARCH),SunOS)
SHELL := ksh
endif
ifeq ($(OS_ARCH),OSF1)
SHELL := ksh
endif
-BUILD_DATE = gbdate.h
-BUILD_DATE_TS = gbdate.tstamp
-
MODULE = layout
LIBRARY_NAME = gklayout
EXPORT_LIBRARY = 1
IS_COMPONENT = 1
MODULE_NAME = nsLayoutModule
GRE_MODULE = 1
LIBXUL_LIBRARY = 1
@@ -107,17 +104,16 @@ REQUIRES = xpcom \
$(NULL)
ifdef MOZ_ENABLE_CAIRO_GFX
REQUIRES += thebes
endif
CPPSRCS = \
nsLayoutModule.cpp \
- nsContentHTTPStartup.cpp \
nsContentDLF.cpp \
nsLayoutStatics.cpp \
$(NULL)
EXPORTS = \
nsLayoutCID.h \
nsContentDLF.h \
nsLayoutStatics.h \
@@ -293,29 +289,13 @@ LOCAL_INCLUDES += -I$(srcdir)/../mathml/
endif
ifdef MOZ_SVG
LOCAL_INCLUDES += -I$(topsrcdir)/content/svg/content/src
endif
DEFINES += -D_IMPL_NS_LAYOUT
-GARBAGE += $(BUILD_DATE) $(BUILD_DATE_TS)
-
ifeq ($(OS_ARCH),IRIX)
ifeq ($(GNU_CXX),1)
LDFLAGS += -Wl,-LD_LAYOUT:lgot_buffer=50
endif
endif
-
-
-export:: $(BUILD_DATE)
-
-$(BUILD_DATE_TS): FORCE
- @for f in $(SHARED_LIBRARY_LIBS); do \
- if [ $$f -nt $@ ]; then \
- touch $@; \
- fi; \
- done
-
-$(BUILD_DATE):: gbdate.pl $(BUILD_DATE_TS)
- $(RM) $@
- $(PERL) $(srcdir)/gbdate.pl > $@
deleted file mode 100644
--- a/layout/build/nsContentHTTPStartup.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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 Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Alec Flett <alecf@netscape.com>
- *
- * 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"),
- * 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 "nsIServiceManager.h"
-#include "nsICategoryManager.h"
-
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsXPIDLString.h"
-#include "nsCRT.h"
-
-#include "nsContentHTTPStartup.h"
-#include "nsIHttpProtocolHandler.h"
-#include "gbdate.h"
-
-#define PRODUCT_NAME "Gecko"
-
-NS_IMPL_ISUPPORTS1(nsContentHTTPStartup,nsIObserver)
-
-nsresult
-nsContentHTTPStartup::Observe( nsISupports *aSubject,
- const char *aTopic,
- const PRUnichar *aData)
-{
- if (nsCRT::strcmp(aTopic, NS_HTTP_STARTUP_TOPIC) != 0)
- return NS_OK;
-
- nsresult rv = nsnull;
-
- nsCOMPtr<nsIHttpProtocolHandler> http(do_QueryInterface(aSubject));
- if (NS_FAILED(rv)) return rv;
-
- rv = http->SetProduct(NS_LITERAL_CSTRING(PRODUCT_NAME));
- if (NS_FAILED(rv)) return rv;
-
- rv = http->SetProductSub(NS_LITERAL_CSTRING(PRODUCT_VERSION));
- if (NS_FAILED(rv)) return rv;
-
- return NS_OK;
-}
-
-nsresult
-nsContentHTTPStartup::RegisterHTTPStartup(nsIComponentManager* aCompMgr,
- nsIFile* aPath,
- const char* aRegistryLocation,
- const char* aComponentType,
- const nsModuleComponentInfo* aInfo)
-{
- nsresult rv;
- nsCOMPtr<nsICategoryManager>
- catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
-
- if (NS_FAILED(rv)) return rv;
-
- nsXPIDLCString previousEntry;
- rv = catMan->AddCategoryEntry(NS_HTTP_STARTUP_CATEGORY,
- "Content UserAgent Setter",
- NS_CONTENTHTTPSTARTUP_CONTRACTID,
- PR_TRUE, PR_TRUE,
- getter_Copies(previousEntry));
- return rv;
-}
-
-nsresult
-nsContentHTTPStartup::UnregisterHTTPStartup(nsIComponentManager* aCompMgr,
- nsIFile* aPath,
- const char* aRegistryLocation,
- const nsModuleComponentInfo* aInfo)
-{
- nsresult rv;
- nsCOMPtr<nsICategoryManager>
- catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
-
- if (NS_FAILED(rv)) return rv;
-
-
- return NS_OK;
-}
deleted file mode 100644
--- a/layout/build/nsContentHTTPStartup.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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 Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Alec Flett <alecf@netscape.com>
- *
- * 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"),
- * 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 "nsIObserver.h"
-
-#define NS_CONTENTHTTPSTARTUP_CONTRACTID \
- "@mozilla.org/content/http-startup;1"
-
-/* c2f6ef7e-afd5-4be4-a1f5-c824efa4231b */
-#define NS_CONTENTHTTPSTARTUP_CID \
-{ 0xc2f6ef7e, 0xafd5, 0x4be4, \
- {0xa1, 0xf5, 0xc8, 0x24, 0xef, 0xa4, 0x23, 0x1b} }
-
-struct nsModuleComponentInfo;
-class nsIFile;
-
-class nsContentHTTPStartup : public nsIObserver
-{
-public:
- nsContentHTTPStartup() { }
- virtual ~nsContentHTTPStartup() {}
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIOBSERVER
-
-public:
- static NS_IMETHODIMP
- RegisterHTTPStartup(nsIComponentManager* aCompMgr,
- nsIFile* aPath,
- const char* aRegistryLocation,
- const char* aComponentType,
- const nsModuleComponentInfo* aInfo);
-
- static NS_IMETHODIMP
- UnregisterHTTPStartup(nsIComponentManager* aCompMgr,
- nsIFile* aPath,
- const char* aRegistryLocation,
- const nsModuleComponentInfo* aInfo);
-
-private:
- nsresult setUserAgent();
-
-};
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -33,17 +33,16 @@
* 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 "nsLayoutStatics.h"
#include "nsContentCID.h"
-#include "nsContentHTTPStartup.h"
#include "nsContentDLF.h"
#include "nsContentPolicyUtils.h"
#include "nsDataDocumentContentPolicy.h"
#include "nsNoDataProtocolContentPolicy.h"
#include "nsDOMCID.h"
#include "nsCSSOMFactory.h"
#include "nsInspectorCSSUtils.h"
#include "nsHTMLContentSerializer.h"
@@ -512,17 +511,16 @@ MAKE_CTOR(CreateXULDocument,
MAKE_CTOR(CreateXULPopupListener, nsIXULPopupListener, NS_NewXULPopupListener)
// NS_NewXULControllers
// NS_NewXULPrototypeCache
#endif
#ifdef MOZ_XTF
MAKE_CTOR(CreateXTFService, nsIXTFService, NS_NewXTFService)
MAKE_CTOR(CreateXMLContentBuilder, nsIXMLContentBuilder, NS_NewXMLContentBuilder)
#endif
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsContentHTTPStartup)
MAKE_CTOR(CreateContentDLF, nsIDocumentLoaderFactory, NS_NewContentDocumentLoaderFactory)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCSSOMFactory)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsInspectorCSSUtils)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWyciwygProtocolHandler)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsContentAreaDragDrop)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDataDocumentContentPolicy)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsNoDataProtocolContentPolicy)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSyncLoadService)
@@ -1213,23 +1211,16 @@ static const nsModuleComponentInfo gComp
CreateXTFService },
{ "XML Content Builder",
NS_XMLCONTENTBUILDER_CID,
NS_XMLCONTENTBUILDER_CONTRACTID,
CreateXMLContentBuilder },
#endif
- { "Content HTTP Startup Listener",
- NS_CONTENTHTTPSTARTUP_CID,
- NS_CONTENTHTTPSTARTUP_CONTRACTID,
- nsContentHTTPStartupConstructor,
- nsContentHTTPStartup::RegisterHTTPStartup,
- nsContentHTTPStartup::UnregisterHTTPStartup },
-
{ "Document Loader Factory",
NS_CONTENT_DOCUMENT_LOADER_FACTORY_CID,
"@mozilla.org/content/document-loader-factory;1",
CreateContentDLF,
nsContentDLF::RegisterDocumentFactories,
nsContentDLF::UnregisterDocumentFactories },
{ "Wyciwyg Handler",
--- a/modules/libreg/src/vr_stubs.c
+++ b/modules/libreg/src/vr_stubs.c
@@ -601,27 +601,20 @@ int strncasecmp(const char *str1, const
#include <io.h>
#define W_OK 0x02 /*evil hack from the docs...*/
#else
#include <unistd.h>
#endif
#include "NSReg.h"
#include "VerReg.h"
-#include "nsBuildID.h"
char *TheRegistry = "registry";
char *Flist;
-/* WARNING: build hackery */
-#if defined(STANDALONE_REGISTRY) && !defined(XP_MAC) && !defined(XP_MACOSX)
-long BUILDNUM = NS_BUILD_ID;
-#endif
-
-
REGERR vr_ParseVersion(char *verstr, VERSION *result);
#if defined(XP_UNIX) && !defined(XP_MACOSX)
#ifdef STANDALONE_REGISTRY
extern XP_File vr_fileOpen (const char *name, const char * mode)
{
XP_File fh = NULL;
--- a/netwerk/protocol/http/src/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/src/nsHttpHandler.cpp
@@ -70,16 +70,18 @@
#include "nsNetCID.h"
#include "nsAutoLock.h"
#include "prprf.h"
#include "nsReadableUtils.h"
#include "nsQuickSort.h"
#include "nsNetUtil.h"
#include "nsIOService.h"
+#include "nsIXULAppInfo.h"
+
#if defined(XP_UNIX) || defined(XP_BEOS)
#include <sys/utsname.h>
#endif
#if defined(XP_WIN)
#include <windows.h>
#endif
@@ -159,16 +161,17 @@ nsHttpHandler::nsHttpHandler()
, mMaxConnectionsPerServer(8)
, mMaxPersistentConnectionsPerServer(2)
, mMaxPersistentConnectionsPerProxy(4)
, mMaxPipelinedRequests(2)
, mRedirectionLimit(10)
, mPhishyUserPassLength(1)
, mLastUniqueID(NowInSeconds())
, mSessionStartTime(0)
+ , mProduct("Gecko")
, mUserAgentIsDirty(PR_TRUE)
, mUseCache(PR_TRUE)
, mSendSecureXSiteReferrer(PR_TRUE)
, mEnablePersistentHttpsCaching(PR_FALSE)
{
#if defined(PR_LOGGING)
gHttpLog = PR_NewLogModule("nsHttp");
#endif
@@ -253,16 +256,21 @@ nsHttpHandler::Init()
mSessionStartTime = NowInSeconds();
rv = mAuthCache.Init();
if (NS_FAILED(rv)) return rv;
rv = InitConnectionMgr();
if (NS_FAILED(rv)) return rv;
+ nsCOMPtr<nsIXULAppInfo> appInfo =
+ do_GetService("@mozilla.org/xre/app-info;1");
+ if (appInfo)
+ appInfo->GetPlatformBuildID(mProductSub);
+
// Startup the http category
// Bring alive the objects in the http-protocol-startup category
NS_CreateServicesFromCategory(NS_HTTP_STARTUP_CATEGORY,
NS_STATIC_CAST(nsISupports*,NS_STATIC_CAST(void*,this)),
NS_HTTP_STARTUP_TOPIC);
mObserverService = do_GetService("@mozilla.org/observer-service;1");
if (mObserverService) {
@@ -811,26 +819,16 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(extraCount, extraItems);
}
}
mUserAgentIsDirty = PR_TRUE;
}
// Gather product values.
- if (PREF_CHANGED(UA_PREF("product"))) {
- prefs->GetCharPref(UA_PREF_PREFIX "product",
- getter_Copies(mProduct));
- mUserAgentIsDirty = PR_TRUE;
- }
- if (PREF_CHANGED(UA_PREF("productSub"))) {
- prefs->GetCharPref(UA_PREF("productSub"),
- getter_Copies(mProductSub));
- mUserAgentIsDirty = PR_TRUE;
- }
if (PREF_CHANGED(UA_PREF("productComment"))) {
prefs->GetCharPref(UA_PREF("productComment"),
getter_Copies(mProductComment));
mUserAgentIsDirty = PR_TRUE;
}
// Get Security level supported
if (PREF_CHANGED(UA_PREF("security"))) {
--- a/netwerk/protocol/http/src/nsHttpHandler.h
+++ b/netwerk/protocol/http/src/nsHttpHandler.h
@@ -279,17 +279,17 @@ private:
nsCString mPlatform;
nsCString mOscpu;
nsXPIDLCString mSecurity;
nsCString mLanguage;
nsCString mMisc;
nsXPIDLCString mVendor;
nsXPIDLCString mVendorSub;
nsXPIDLCString mVendorComment;
- nsXPIDLCString mProduct;
+ nsCString mProduct;
nsXPIDLCString mProductSub;
nsXPIDLCString mProductComment;
nsCString mExtraUA;
nsCString mUserAgent;
nsXPIDLCString mUserAgentOverride;
PRPackedBool mUserAgentIsDirty; // true if mUserAgent should be rebuilt
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -88,17 +88,16 @@ endif
ifdef MOZ_AIRBAG
REQUIRES += airbag
endif
FORCE_STATIC_LIB = 1
XPIDLSRCS = \
nsINativeAppSupport.idl \
- nsIXULAppInfo.idl \
nsIXULRuntime.idl \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
XPIDLSRCS += nsIWinAppHelper.idl
endif
EXPORTS = \
@@ -248,8 +247,17 @@ endif
DEFINES += -DTOOLKIT_EM_VERSION=\"$(shell $(PERL) $(topsrcdir)/config/milestone.pl --topsrcdir=$(topsrcdir))\"
ifdef WRAP_SYSTEM_INCLUDES
DEFINES += -DWRAP_SYSTEM_INCLUDES
endif
export:: $(addprefix $(topsrcdir)/xpfe/bootstrap/, $(SHAREDCPPSRCS)) $(STACKWALK_CPPSRCS)
$(INSTALL) $^ .
+
+platform.ini: FORCE
+ $(PYTHON) $(srcdir)/make-platformini.py $(topsrcdir)/config/milestone.txt > $@
+
+libs:: platform.ini
+ $(INSTALL) $^ $(DIST)/bin
+
+install::
+ $(INSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/make-platformini.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+from optparse import OptionParser
+from datetime import datetime
+import sys
+import os
+
+o = OptionParser()
+o.add_option("--print-buildid", action="store_true", dest="print_buildid")
+
+(options, args) = o.parse_args()
+buildid = os.environ.get('MOZ_BUILD_DATE', datetime.now().strftime('%Y%m%d%H'))
+
+if options.print_buildid:
+ print buildid
+ sys.exit(0)
+
+(milestoneFile,) = args
+for line in open(milestoneFile, 'r'):
+ if line[0] == '#':
+ continue
+
+ line = line.strip()
+ if line == '':
+ continue
+
+ milestone = line
+
+print """[Build]
+BuildID=%s
+Milestone=%s""" % (buildid, milestone)
--- a/toolkit/xre/nsAppData.cpp
+++ b/toolkit/xre/nsAppData.cpp
@@ -64,16 +64,18 @@ SetAllocatedString(const char *&str, con
str = ToNewCString(newvalue);
}
}
ScopedAppData::ScopedAppData(const nsXREAppData* aAppData)
{
Zero();
+ this->size = aAppData->size;
+
SetAllocatedString(this->vendor, aAppData->vendor);
SetAllocatedString(this->name, aAppData->name);
SetAllocatedString(this->version, aAppData->version);
SetAllocatedString(this->buildID, aAppData->buildID);
SetAllocatedString(this->ID, aAppData->ID);
SetAllocatedString(this->copyright, aAppData->copyright);
SetStrongPtr(this->directory, aAppData->directory);
this->flags = aAppData->flags;
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -41,17 +41,16 @@
*
* ***** END LICENSE BLOCK ***** */
#define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1
#include "nsAppRunner.h"
#include "nsUpdateDriver.h"
-#include "nsBuildID.h"
#ifdef XP_MACOSX
#include "MacLaunchHelper.h"
#include "MacApplicationDelegate.h"
#endif
#ifdef XP_OS2
#include "private/pprthred.h"
@@ -261,16 +260,19 @@ extern "C" {
#if defined(XP_UNIX) || defined(XP_BEOS)
extern void InstallUnixSignalHandlers(const char *ProgramName);
#endif
int gArgc;
char **gArgv;
+static char gToolkitVersion[20];
+static char gToolkitBuildID[40];
+
static int gRestartArgc;
static char **gRestartArgv;
#if defined(MOZ_WIDGET_GTK2)
#include <gtk/gtk.h>
#include "nsGTKToolkit.h"
#endif
@@ -585,33 +587,33 @@ nsXULAppInfo::GetVersion(nsACString& aRe
aResult.Assign(gAppData->version);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
{
- aResult.AssignLiteral(TOOLKIT_EM_VERSION);
+ aResult.AssignLiteral(gToolkitVersion);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetAppBuildID(nsACString& aResult)
{
aResult.Assign(gAppData->buildID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
{
- aResult.Assign(NS_STRINGIFY(BUILD_ID));
+ aResult.Assign(gToolkitBuildID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetLogConsoleErrors(PRBool *aResult)
{
*aResult = gLogConsoleErrors;
@@ -1975,17 +1977,17 @@ CheckCompatibility(nsIFile* aProfileDir,
}
static void BuildVersion(nsCString &aBuf)
{
aBuf.Assign(gAppData->version);
aBuf.Append('_');
aBuf.Append(gAppData->buildID);
aBuf.Append('/');
- aBuf.AppendLiteral(GRE_BUILD_ID);
+ aBuf.Append(gToolkitBuildID);
}
static void
WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
const nsCString& aOSABI, nsIFile* aXULRunnerDir,
nsIFile* aAppDir)
{
nsCOMPtr<nsIFile> file;
@@ -2300,37 +2302,16 @@ XRE_main(int argc, char* argv[], const n
Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
return 1;
}
if (!appData.buildID) {
Output(PR_TRUE, "Error: App:BuildID not specified in application.ini\n");
return 1;
}
- if (appData.size > offsetof(nsXREAppData, minVersion)) {
- if (!appData.minVersion) {
- Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
- return 1;
- }
-
- if (!appData.maxVersion) {
- // If no maxVersion is specified, we assume the app is only compatible
- // with the initial preview release. Do not increment this number ever!
- SetAllocatedString(appData.maxVersion, "1.*");
- }
-
- if (NS_CompareVersions(appData.minVersion, TOOLKIT_EM_VERSION) > 0 ||
- NS_CompareVersions(appData.maxVersion, TOOLKIT_EM_VERSION) < 0) {
- Output(PR_TRUE, "Error: Platform version " TOOLKIT_EM_VERSION " is not compatible with\n"
- "minVersion >= %s\nmaxVersion <= %s\n",
- appData.minVersion, appData.maxVersion);
- return 1;
- }
- }
-
ScopedLogging log;
if (!appData.xreDirectory) {
nsCOMPtr<nsILocalFile> lf;
rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
if (NS_FAILED(rv))
return 2;
@@ -2339,16 +2320,64 @@ XRE_main(int argc, char* argv[], const n
if (NS_FAILED(rv))
return 2;
rv = CallQueryInterface(greDir, &appData.xreDirectory);
if (NS_FAILED(rv))
return 2;
}
+ nsCOMPtr<nsIFile> iniFile;
+ rv = appData.xreDirectory->Clone(getter_AddRefs(iniFile));
+ if (NS_FAILED(rv))
+ return 2;
+
+ iniFile->AppendNative(NS_LITERAL_CSTRING("platform.ini"));
+
+ nsCOMPtr<nsILocalFile> localIniFile = do_QueryInterface(iniFile);
+ if (!localIniFile)
+ return 2;
+
+ nsINIParser parser;
+ rv = parser.Init(localIniFile);
+ if (NS_SUCCEEDED(rv)) {
+ rv = parser.GetString("Build", "Milestone",
+ gToolkitVersion, sizeof(gToolkitVersion));
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit version");
+
+ rv = parser.GetString("Build", "BuildID",
+ gToolkitBuildID, sizeof(gToolkitBuildID));
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit buildid");
+ }
+ else {
+ NS_ERROR("Couldn't parse platform.ini!");
+ }
+
+ if (appData.size > offsetof(nsXREAppData, minVersion)) {
+ if (!appData.minVersion) {
+ Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
+ return 1;
+ }
+
+ if (!appData.maxVersion) {
+ // If no maxVersion is specified, we assume the app is only compatible
+ // with the initial preview release. Do not increment this number ever!
+ SetAllocatedString(appData.maxVersion, "1.*");
+ }
+
+ if (NS_CompareVersions(appData.minVersion, gToolkitVersion) > 0 ||
+ NS_CompareVersions(appData.maxVersion, gToolkitVersion) < 0) {
+ Output(PR_TRUE, "Error: Platform version '%s' is not compatible with\n"
+ "minVersion >= %s\nmaxVersion <= %s\n",
+ gToolkitVersion,
+ appData.minVersion, appData.maxVersion);
+ return 1;
+ }
+ }
+
#ifdef MOZ_AIRBAG
const char* airbagEnv = PR_GetEnv("MOZ_CRASHREPORTER");
if (airbagEnv && *airbagEnv) {
appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
}
if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
NS_SUCCEEDED(
deleted file mode 100644
--- a/toolkit/xre/nsIXULAppInfo.idl
+++ /dev/null
@@ -1,92 +0,0 @@
-/* ***** 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 XUL bootstrap code.
- *
- * The Initial Developer of the Original Code is
- * Benjamin Smedberg <benjamin@smedbergs.us>
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * 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 ***** */
-
-#include "nsISupports.idl"
-
-/**
- * A scriptable interface to the nsXULAppAPI structure. See nsXULAppAPI.h for
- * a detailed description of each attribute.
- *
- * @status FROZEN - This interface is frozen for use by embedders and will
- * not change in the future.
- */
-
-[scriptable, uuid(a61ede2a-ef09-11d9-a5ce-001124787b2e)]
-interface nsIXULAppInfo : nsISupports
-{
- /**
- * @see nsXREAppData.vendor
- * @returns an empty string if nsXREAppData.vendor is not set.
- */
- readonly attribute ACString vendor;
-
- /**
- * @see nsXREAppData.name
- */
- readonly attribute ACString name;
-
- /**
- * @see nsXREAppData.ID
- * @returns an empty string if nsXREAppData.ID is not set.
- */
- readonly attribute ACString ID;
-
- /**
- * The version of the XUL application. It is different than the
- * version of the XULRunner platform. Be careful about which one you want.
- *
- * @see nsXREAppData.version
- * @returns an empty string if nsXREAppData.version is not set.
- */
- readonly attribute ACString version;
-
- /**
- * The build ID/date of the application. For xulrunner applications,
- * this will be different than the build ID of the platform. Be careful
- * about which one you want.
- */
- readonly attribute ACString appBuildID;
-
- /**
- * The version of the XULRunner platform.
- */
- readonly attribute ACString platformVersion;
-
- /**
- * The build ID/date of gecko and the XULRunner platform.
- */
- readonly attribute ACString platformBuildID;
-};
--- a/xpcom/glue/standalone/Makefile.in
+++ b/xpcom/glue/standalone/Makefile.in
@@ -79,17 +79,16 @@ endif
CSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(NULL)
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCPPSRCS) \
nsXPCOMGlue.cpp \
- nsGREDirServiceProvider.cpp \
$(LINKSRC) \
$(NULL)
SDK_HEADERS = \
nsXPCOMGlue.h \
$(NULL)
SDK_LIBRARY = \
deleted file mode 100644
--- a/xpcom/glue/standalone/nsGREDirServiceProvider.cpp
+++ /dev/null
@@ -1,320 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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 Communicator.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corp.
- * Portions created by the Initial Developer are Copyright (C) 2003
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Sean Su <ssu@netscape.com>
- * Benjamin Smedberg <benjamin@smedbergs.us>
- *
- * 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 "nsBuildID.h"
-
-#include "nsEmbedString.h"
-#include "nsXPCOMPrivate.h"
-#include "nsXPCOMGlue.h"
-#include "nsILocalFile.h"
-#include "nsIDirectoryService.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsCOMPtr.h"
-#include "nsMemory.h"
-
-#include "nspr.h"
-#include "plstr.h"
-
-#ifdef XP_WIN32
-#include <windows.h>
-#include <stdlib.h>
-#include <mbstring.h>
-#elif defined(XP_OS2)
-#define INCL_DOS
-#include <os2.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "prenv.h"
-#elif defined(XP_MACOSX)
-#include <Processes.h>
-#include <CFBundle.h>
-#elif defined(XP_UNIX)
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/param.h>
-#include "prenv.h"
-#elif defined(XP_BEOS)
-#include <stdlib.h>
-#include <image.h>
-#endif
-
-#include <sys/stat.h>
-
-#include "nsGREDirServiceProvider.h"
-
-static PRBool GRE_GetCurrentProcessDirectory(char* buffer);
-
-//*****************************************************************************
-// nsGREDirServiceProvider::nsISupports
-//*****************************************************************************
-
-NS_IMPL_ISUPPORTS1(nsGREDirServiceProvider, nsIDirectoryServiceProvider)
-
-//*****************************************************************************
-// nsGREDirServiceProvider::nsIDirectoryServiceProvider
-//*****************************************************************************
-
-NS_IMETHODIMP
-nsGREDirServiceProvider::GetFile(const char *prop, PRBool *persistent, nsIFile **_retval)
-{
- *_retval = nsnull;
- *persistent = PR_TRUE;
-
- //---------------------------------------------------------------
- // Note that by returning a valid localFile's for NS_GRE_DIR,
- // your app is indicating to XPCOM that it found a GRE version
- // with which it's compatible with and intends to be "run against"
- // that GRE.
- //
- // Please see http://www.mozilla.org/projects/embedding/GRE.html
- // for more info on GRE.
- //---------------------------------------------------------------
- if(strcmp(prop, NS_GRE_DIR) == 0)
- {
- nsILocalFile* lfile = nsnull;
- nsresult rv = GRE_GetGREDirectory(&lfile);
- *_retval = lfile;
- return rv;
- }
-
- return NS_ERROR_FAILURE;
-}
-
-//*****************************************************************************
-// Implementations from nsXPCOMGlue.h and helper functions.
-//*****************************************************************************
-
-PRBool
-GRE_GetCurrentProcessDirectory(char* buffer)
-{
- *buffer = '\0';
-
-#ifdef XP_WIN
- DWORD bufLength = ::GetModuleFileName(0, buffer, MAXPATHLEN);
- if (bufLength == 0 || bufLength == MAXPATHLEN)
- return PR_FALSE;
- // chop of the executable name by finding the rightmost backslash
- unsigned char* lastSlash = _mbsrchr((unsigned char*) buffer, '\\');
- if (lastSlash) {
- *(lastSlash) = '\0';
- return PR_TRUE;
- }
-
-#elif defined(XP_MACOSX)
- // Works even if we're not bundled.
- CFBundleRef appBundle = CFBundleGetMainBundle();
- if (appBundle != nsnull)
- {
- CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle);
- if (bundleURL != nsnull)
- {
- CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL);
- if (parentURL)
- {
- CFStringRef path = CFURLCopyFileSystemPath(parentURL, kCFURLPOSIXPathStyle);
- if (path)
- {
- CFStringGetCString(path, buffer, MAXPATHLEN, kCFStringEncodingUTF8);
- CFRelease(path);
- }
- CFRelease(parentURL);
- }
- CFRelease(bundleURL);
- }
- }
- if (*buffer) return PR_TRUE;
-
-#elif defined(XP_UNIX)
-
- // In the absence of a good way to get the executable directory let
- // us try this for unix:
- // - if MOZILLA_FIVE_HOME is defined, that is it
- // - else give the current directory
-
- // The MOZ_DEFAULT_MOZILLA_FIVE_HOME variable can be set at configure time with
- // a --with-default-mozilla-five-home=foo autoconf flag.
- //
- // The idea here is to allow for builds that have a default MOZILLA_FIVE_HOME
- // regardless of the environment. This makes it easier to write apps that
- // embed mozilla without having to worry about setting up the environment
- //
- // We do this py putenv()ing the default value into the environment. Note that
- // we only do this if it is not already set.
-#ifdef MOZ_DEFAULT_MOZILLA_FIVE_HOME
- if (getenv("MOZILLA_FIVE_HOME") == nsnull)
- {
- putenv("MOZILLA_FIVE_HOME=" MOZ_DEFAULT_MOZILLA_FIVE_HOME);
- }
-#endif
-
- char *moz5 = getenv("MOZILLA_FIVE_HOME");
-
- if (moz5 && *moz5)
- {
- if (!realpath(moz5, buffer))
- strcpy(buffer, moz5);
-
- return PR_TRUE;
- }
- else
- {
-#if defined(DEBUG)
- static PRBool firstWarning = PR_TRUE;
-
- if(firstWarning) {
- // Warn that MOZILLA_FIVE_HOME not set, once.
- printf("Warning: MOZILLA_FIVE_HOME not set.\n");
- firstWarning = PR_FALSE;
- }
-#endif /* DEBUG */
-
- // Fall back to current directory.
- if (getcwd(buffer, MAXPATHLEN))
- {
- return PR_TRUE;
- }
- }
-
-#elif defined(XP_OS2)
- PPIB ppib;
- PTIB ptib;
- char* p;
- DosGetInfoBlocks( &ptib, &ppib);
- DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, buffer);
- p = strrchr( buffer, '\\'); // XXX DBCS misery
- if (p) {
- *p = '\0';
- return PR_TRUE;
- }
-
-#elif defined(XP_BEOS)
-// We are able to get actual path for running app.
- int32 cookie = 0;
- image_info info;
- char *lastSlash;
- *buffer = 0;
- if (get_next_image_info(0, &cookie, &info) == B_OK)
- {
- strcpy(buffer, info.name);
- if ((lastSlash = strrchr(buffer, '/')) != 0)
- {
- *lastSlash = '\0';
- return PR_TRUE;
- }
- }
-
-#endif
-
- return PR_FALSE;
-}
-
-/**
- * the GRE location is stored in a static buffer so that we don't have
- * to compute it multiple times.
- */
-
-static char sXPCOMPath[MAXPATHLEN] = "";
-
-extern "C" char const *
-GRE_GetXPCOMPath()
-{
- // we've already done this...
- if (*sXPCOMPath)
- return sXPCOMPath;
-
- char buffer[MAXPATHLEN];
-
- // If the xpcom library exists in the current process directory,
- // then we will not use any GRE. The assumption here is that the
- // GRE is in the same directory as the executable.
- if (GRE_GetCurrentProcessDirectory(buffer)) {
- PRUint32 pathlen = strlen(buffer);
- strcpy(buffer + pathlen, XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL);
-
- struct stat libStat;
- int statResult = stat(buffer, &libStat);
-
- if (statResult != -1) {
- //found our xpcom lib in the current process directory
- strcpy(sXPCOMPath, buffer);
- return sXPCOMPath;
- }
- }
-
- static const GREVersionRange version = {
- GRE_BUILD_ID, PR_TRUE,
- GRE_BUILD_ID, PR_TRUE
- };
-
- GRE_GetGREPathWithProperties(&version, 1,
- nsnull, 0,
- sXPCOMPath, MAXPATHLEN);
- if (*sXPCOMPath)
- return sXPCOMPath;
-
- return nsnull;
-}
-
-extern "C" nsresult
-GRE_GetGREDirectory(nsILocalFile* *_retval)
-{
- NS_ENSURE_ARG_POINTER(_retval);
- nsresult rv = NS_ERROR_FAILURE;
-
- // Get the path of the GRE which is compatible with our embedding application
- // from the registry
-
- const char *pGREDir = GRE_GetXPCOMPath();
- if(!pGREDir)
- return NS_ERROR_FAILURE;
-
- nsCOMPtr<nsILocalFile> xpcomPath;
- nsEmbedCString leaf(pGREDir);
- rv = NS_NewNativeLocalFile(leaf, PR_TRUE, getter_AddRefs(xpcomPath));
-
- if (NS_FAILED(rv))
- return rv;
-
- nsCOMPtr<nsIFile> directory;
- rv = xpcomPath->GetParent(getter_AddRefs(directory));
- if (NS_FAILED(rv))
- return rv;
-
- return CallQueryInterface(directory, _retval);
-}
deleted file mode 100644
--- a/xpcom/glue/standalone/nsGREDirServiceProvider.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ***** 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 Communicator.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corp.
- * Portions created by the Initial Developer are Copyright (C) 2003
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Sean Su <ssu@netscape.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 ***** */
-
-#ifndef nsGREDirServiceProvider_h_
-#define nsGREDirServiceProvider_h_
-
-#include "nsIDirectoryService.h"
-
-/**
- * the directoryserviceprovider used by GRE_Startup when calling NS_InitXPCOM2
- */
-class nsGREDirServiceProvider : public nsIDirectoryServiceProvider
-{
-public:
- nsGREDirServiceProvider() { }
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDIRECTORYSERVICEPROVIDER
-
-private:
- ~nsGREDirServiceProvider() { }
-};
-
-#endif // nsGREDirServiceProvider.h
--- a/xpcom/glue/standalone/nsXPCOMGlue.cpp
+++ b/xpcom/glue/standalone/nsXPCOMGlue.cpp
@@ -37,17 +37,16 @@
* ***** END LICENSE BLOCK ***** */
#include "nsXPCOMGlue.h"
#include "nsGlueLinking.h"
#include "nspr.h"
#include "nsDebug.h"
#include "nsIServiceManager.h"
-#include "nsGREDirServiceProvider.h"
#include "nsXPCOMPrivate.h"
#include "nsCOMPtr.h"
#include <stdlib.h>
#include <stdio.h>
#ifdef XP_WIN
#include <windows.h>
#include <mbstring.h>
@@ -513,73 +512,8 @@ NS_InvokeByIndex(nsISupports* that, PRUi
PRUint32 paramCount, nsXPTCVariant* params)
{
if (!xpcomFunctions.invokeByIndexFunc)
return NS_ERROR_NOT_INITIALIZED;
return xpcomFunctions.invokeByIndexFunc(that, methodIndex,
paramCount, params);
}
-
-// Default GRE startup/shutdown code
-
-extern "C"
-nsresult GRE_Startup()
-{
- const char* xpcomLocation = GRE_GetXPCOMPath();
-
- // Startup the XPCOM Glue that links us up with XPCOM.
- nsresult rv = XPCOMGlueStartup(xpcomLocation);
-
- if (NS_FAILED(rv)) {
- NS_WARNING("gre: XPCOMGlueStartup failed");
- return rv;
- }
-
-#ifdef XP_WIN
- // On windows we have legacy GRE code that does not load the GRE dependent
- // libs (seamonkey GRE, not libxul)... add the GRE to the PATH.
- // See bug 301043.
-
- const char *lastSlash = strrchr(xpcomLocation, '\\');
- if (lastSlash) {
- int xpcomPathLen = lastSlash - xpcomLocation;
- DWORD pathLen = GetEnvironmentVariable("PATH", nsnull, 0);
-
- char *newPath = (char*) _alloca(xpcomPathLen + pathLen + 1);
- strncpy(newPath, xpcomLocation, xpcomPathLen);
- // in case GetEnvironmentVariable fails
- newPath[xpcomPathLen] = ';';
- newPath[xpcomPathLen + 1] = '\0';
-
- GetEnvironmentVariable("PATH", newPath + xpcomPathLen + 1, pathLen);
- SetEnvironmentVariable("PATH", newPath);
- }
-#endif
-
- nsGREDirServiceProvider *provider = new nsGREDirServiceProvider();
- if ( !provider ) {
- NS_WARNING("GRE_Startup failed");
- XPCOMGlueShutdown();
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- nsCOMPtr<nsIServiceManager> servMan;
- NS_ADDREF( provider );
- rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, provider);
- NS_RELEASE(provider);
-
- if ( NS_FAILED(rv) || !servMan) {
- NS_WARNING("gre: NS_InitXPCOM failed");
- XPCOMGlueShutdown();
- return rv;
- }
-
- return NS_OK;
-}
-
-extern "C"
-nsresult GRE_Shutdown()
-{
- NS_ShutdownXPCOM(nsnull);
- XPCOMGlueShutdown();
- return NS_OK;
-}
--- a/xpcom/glue/standalone/nsXPCOMGlue.h
+++ b/xpcom/glue/standalone/nsXPCOMGlue.h
@@ -122,50 +122,10 @@ extern "C" NS_HIDDEN_(nsresult)
XPCOMGlueLoadXULFunctions(const nsDynamicFunctionLoad *symbols);
/**
* Finish the XPCOM glue after it is no longer needed.
*/
extern "C" NS_HIDDEN_(nsresult)
XPCOMGlueShutdown();
-
-/**
- * Locate the path of the XPCOM shared library of a compatible GRE.
- * The result of this function is normally passed directly to
- * XPCOMGlueStartup. This looks for the GRE version in
- * nsBuildID.h, which is generated at build time. Unless you set
- * MOZ_MILESTONE_RELEASE this will probably not be a useful GRE version string.
- *
- * @return string buffer pointing to the XPCOM DLL path. Callers do
- * not need to free this buffer.
- * @status DEPRECATED - Use GRE_GetGREPathWithProperties
- */
-extern "C" NS_HIDDEN_(char const *)
-GRE_GetXPCOMPath();
-
-
-/**
- * Locate the directory of a compatible GRE as an nsIFile
- *
- * @param _retval Ordinary XPCOM getter, returns an addrefed interface.
- */
-extern "C" NS_HIDDEN_(nsresult)
-GRE_GetGREDirectory(nsILocalFile* *_retval);
-
-
-/**
- * Embedding applications which don't need a custom
- * directoryserviceprovider may use GRE_Startup to start the XPCOM
- * glue and initialize the GRE in one step.
- */
-extern "C" NS_HIDDEN_(nsresult)
-GRE_Startup();
-
-
-/**
- * Shut down XPCOM and the XPCOM glue in one step.
- */
-extern "C" NS_HIDDEN_(nsresult)
-GRE_Shutdown();
-
#endif // XPCOM_GLUE
#endif // nsXPCOMGlue_h__
--- a/xpcom/system/Makefile.in
+++ b/xpcom/system/Makefile.in
@@ -41,13 +41,14 @@ srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xpcom
XPIDL_MODULE = xpcom_system
XPIDLSRCS = \
+ nsIXULAppInfo.idl \
nsIGConfService.idl \
nsIGnomeVFSService.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/xpcom/system/nsIXULAppInfo.idl
@@ -0,0 +1,92 @@
+/* ***** 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 XUL bootstrap code.
+ *
+ * The Initial Developer of the Original Code is
+ * Benjamin Smedberg <benjamin@smedbergs.us>
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * 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 ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * A scriptable interface to the nsXULAppAPI structure. See nsXULAppAPI.h for
+ * a detailed description of each attribute.
+ *
+ * @status FROZEN - This interface is frozen for use by embedders and will
+ * not change in the future.
+ */
+
+[scriptable, uuid(a61ede2a-ef09-11d9-a5ce-001124787b2e)]
+interface nsIXULAppInfo : nsISupports
+{
+ /**
+ * @see nsXREAppData.vendor
+ * @returns an empty string if nsXREAppData.vendor is not set.
+ */
+ readonly attribute ACString vendor;
+
+ /**
+ * @see nsXREAppData.name
+ */
+ readonly attribute ACString name;
+
+ /**
+ * @see nsXREAppData.ID
+ * @returns an empty string if nsXREAppData.ID is not set.
+ */
+ readonly attribute ACString ID;
+
+ /**
+ * The version of the XUL application. It is different than the
+ * version of the XULRunner platform. Be careful about which one you want.
+ *
+ * @see nsXREAppData.version
+ * @returns an empty string if nsXREAppData.version is not set.
+ */
+ readonly attribute ACString version;
+
+ /**
+ * The build ID/date of the application. For xulrunner applications,
+ * this will be different than the build ID of the platform. Be careful
+ * about which one you want.
+ */
+ readonly attribute ACString appBuildID;
+
+ /**
+ * The version of the XULRunner platform.
+ */
+ readonly attribute ACString platformVersion;
+
+ /**
+ * The build ID/date of gecko and the XULRunner platform.
+ */
+ readonly attribute ACString platformBuildID;
+};
--- a/xpinstall/src/nsJSInstall.cpp
+++ b/xpinstall/src/nsJSInstall.cpp
@@ -36,17 +36,16 @@
*
* ***** END LICENSE BLOCK ***** */
#include "jsapi.h"
#include "nsJSFile.h"
#include "nscore.h"
#include "nsIScriptContext.h"
-#include "nsBuildID.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsInstall.h"
#include "nsInstallFile.h"
#include "nsInstallTrigger.h"
#include "nsIPromptService.h"
#include "nsIDOMInstallVersion.h"
@@ -1851,18 +1850,16 @@ static JSConstDoubleSpec install_constan
{ CHROME_SKIN, "SKIN" },
{ CHROME_LOCALE, "LOCALE" },
{ CHROME_CONTENT, "CONTENT" },
{ CHROME_ALL, "PACKAGE" },
{ CHROME_PROFILE, "PROFILE_CHROME" },
{ CHROME_DELAYED, "DELAYED_CHROME" },
{ CHROME_SELECT, "SELECT_CHROME" },
- { NS_BUILD_ID, "buildID" },
-
{0}
};
//
// Install class methods
//
static JSFunctionSpec InstallMethods[] =
{
--- a/xpinstall/src/nsSoftwareUpdate.cpp
+++ b/xpinstall/src/nsSoftwareUpdate.cpp
@@ -64,17 +64,16 @@
#include "nsInstallVersion.h"
#include "ScheduledTasks.h"
#include "InstallCleanupDefines.h"
#include "nsXPInstallManager.h"
#include "nsTopProgressNotifier.h"
#include "nsLoggingProgressNotifier.h"
-#include "nsBuildID.h"
#include "nsProcess.h"
/* For Javascript Namespace Access */
#include "nsDOMCID.h"
#include "nsIServiceManager.h"
#include "nsIScriptNameSpaceManager.h"
#include "nsIScriptExternalNameSet.h"
--- a/xulrunner/app/nsRegisterGRE.h
+++ b/xulrunner/app/nsRegisterGRE.h
@@ -34,22 +34,25 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsRegisterGRE_h__
#define nsRegisterGRE_h__
#include "nscore.h"
+#include "nsStringAPI.h"
class nsIFile;
struct GREProperty;
/**
* @return PR_TRUE on success
*/
NS_HIDDEN_(PRBool)
RegisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation,
- const GREProperty *aProperties, PRUint32 aPropertiesLen);
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone);
NS_HIDDEN_(void)
-UnregisterXULRunner(PRBool aUnregisterGlobally, nsIFile* aLocation);
+UnregisterXULRunner(PRBool aUnregisterGlobally, nsIFile* aLocation,
+ const char *aGREMilestone);
#endif // nsRegisterGRE_h__
--- a/xulrunner/app/nsRegisterGREUnix.cpp
+++ b/xulrunner/app/nsRegisterGREUnix.cpp
@@ -37,17 +37,16 @@
#include "nsRegisterGRE.h"
#include "nsXPCOMGlue.h"
#include "nsXPCOM.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
-#include "nsBuildID.h"
#include "nsAppRunner.h" // for MAXPATHLEN
#include "nsStringAPI.h"
#include "nsINIParser.h"
#include "nsCOMPtr.h"
#include "prio.h"
#include "prprf.h"
#include "prenv.h"
@@ -57,17 +56,16 @@
// If we can't register <buildid>.conf, we try to create a unique filename
// by looping through <buildid>_<int>.conf, but if something is seriously wrong
// we stop at 1000
#define UNIQ_LOOP_LIMIT 1000
static const char kRegFileGlobal[] = "global.reginfo";
static const char kRegFileUser[] = "user.reginfo";
-static const char kGREBuildID[] = GRE_BUILD_ID;
class AutoFDClose
{
public:
AutoFDClose(PRFileDesc* fd = nsnull) : mFD(fd) { }
~AutoFDClose() { if (mFD) PR_Close(mFD); }
PRFileDesc* operator= (PRFileDesc *fd) {
@@ -80,60 +78,57 @@ public:
PRFileDesc** operator &() { *this = nsnull; return &mFD; }
private:
PRFileDesc *mFD;
};
static PRBool
MakeConfFile(const char *regfile, const nsCString &greHome,
- const GREProperty *aProperties, PRUint32 aPropertiesLen)
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone)
{
// If the file exists, don't create it again!
if (access(regfile, R_OK) == 0)
return PR_FALSE;
PRBool ok = PR_TRUE;
{ // scope "fd" so that we can delete the file if something goes wrong
AutoFDClose fd = PR_Open(regfile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE,
0664);
if (!fd)
return PR_FALSE;
static const char kHeader[] =
"# Registration file generated by xulrunner. Do not edit.\n\n"
- "[" GRE_BUILD_ID "]\n"
- "GRE_PATH=";
+ "[%s]\n"
+ "GRE_PATH=%s\n";
- if (PR_Write(fd, kHeader, sizeof(kHeader) - 1) != sizeof(kHeader) - 1)
- ok = PR_FALSE;
-
- if (PR_Write(fd, greHome.get(), greHome.Length()) != greHome.Length())
+ if (PR_fprintf(fd, kHeader, aGREMilestone, greHome.get()) <= 0)
ok = PR_FALSE;
for (PRUint32 i = 0; i < aPropertiesLen; ++i) {
- if (PR_fprintf(fd, "\n%s=%s",
+ if (PR_fprintf(fd, "%s=%s\n",
aProperties[i].property, aProperties[i].value) <= 0)
ok = PR_FALSE;
}
-
- PR_Write(fd, "\n", 1);
}
if (!ok)
PR_Delete(regfile);
return ok;
}
PRBool
RegisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation,
- const GREProperty *aProperties, PRUint32 aPropertiesLen)
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone)
{
// Register ourself in /etc/gre.d or ~/.gre.d/ and record what key we created
// for future unregistration.
nsresult rv;
char root[MAXPATHLEN] = "/etc/gre.d";
@@ -193,39 +188,42 @@ RegisterXULRunner(PRBool aRegisterGlobal
if (access(root, R_OK | X_OK) &&
mkdir(root, 0775)) {
fprintf(stderr, "Error: could not create '%s'.\n",
root);
return PR_FALSE;
}
- PR_snprintf(regfile, MAXPATHLEN, "%s/%s.conf", root, kGREBuildID);
- if (MakeConfFile(regfile, greHome, aProperties, aPropertiesLen)) {
- PR_Write(fd, kGREBuildID, sizeof(kGREBuildID) - 1);
+ PR_snprintf(regfile, MAXPATHLEN, "%s/%s.conf", root, aGREMilestone);
+ if (MakeConfFile(regfile, greHome, aProperties, aPropertiesLen,
+ aGREMilestone)) {
+ PR_fprintf(fd, "%s", aGREMilestone);
return PR_TRUE;
}
for (int i = 0; i < UNIQ_LOOP_LIMIT; ++i) {
static char buildID[30];
- sprintf(buildID, "%s_%i", kGREBuildID, i);
+ sprintf(buildID, "%s_%i", aGREMilestone, i);
PR_snprintf(regfile, MAXPATHLEN, "%s/%s.conf", root, buildID);
- if (MakeConfFile(regfile, greHome, aProperties, aPropertiesLen)) {
+ if (MakeConfFile(regfile, greHome, aProperties, aPropertiesLen,
+ aGREMilestone)) {
PR_Write(fd, buildID, strlen(buildID));
return PR_TRUE;
}
}
return PR_FALSE;
}
void
-UnregisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation)
+UnregisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation,
+ const char *aGREMilestone)
{
nsresult rv;
char root[MAXPATHLEN] = "/etc/gre.d";
if (!aRegisterGlobally) {
char *home = PR_GetEnv("HOME");
if (!home || !*home)
@@ -270,17 +268,17 @@ UnregisterXULRunner(PRBool aRegisterGlob
if (NS_FAILED(rv))
return;
nsINIParser p;
rv = p.Init(lf);
if (NS_FAILED(rv))
return;
- rv = p.GetString(kGREBuildID, "GRE_PATH", root, MAXPATHLEN);
+ rv = p.GetString(aGREMilestone, "GRE_PATH", root, MAXPATHLEN);
if (NS_FAILED(rv))
return;
rv = NS_NewNativeLocalFile(nsDependentCString(root), PR_TRUE,
getter_AddRefs(lf));
if (NS_FAILED(rv))
return;
--- a/xulrunner/app/nsRegisterGREVoid.cpp
+++ b/xulrunner/app/nsRegisterGREVoid.cpp
@@ -37,19 +37,21 @@
#include "nsRegisterGRE.h"
#include <stdlib.h>
#include <stdio.h>
int
RegisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation,
- const GREProperty *aProperties, PRUint32 aPropertiesLen)
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone)
{
fprintf(stderr, "Registration not implemented on this platform!\n");
return 1;
}
void
-UnregisterXULRunner(PRBool aUnregisterGlobally, nsIFile* aLocation)
+UnregisterXULRunner(PRBool aUnregisterGlobally, nsIFile* aLocation,
+ const char *aGREMilestone)
{
fprintf(stderr, "Registration not implemented on this platform!\n");
}
--- a/xulrunner/app/nsRegisterGREWin.cpp
+++ b/xulrunner/app/nsRegisterGREWin.cpp
@@ -36,49 +36,49 @@
* ***** END LICENSE BLOCK ***** */
#include "nsRegisterGRE.h"
#include "nsXPCOM.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
-#include "nsBuildID.h"
#include "nsAppRunner.h" // for MAXPATHLEN
#include "nsStringAPI.h"
#include "nsXPCOMGlue.h"
#include "nsCOMPtr.h"
#include "prio.h"
#include <windows.h>
static const char kRegKeyRoot[] = "Software\\mozilla.org\\GRE";
static const char kRegFileGlobal[] = "global.reginfo";
static const char kRegFileUser[] = "user.reginfo";
static nsresult
MakeVersionKey(HKEY root, const char* keyname, const nsCString &grehome,
- const GREProperty *aProperties, PRUint32 aPropertiesLen)
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone)
{
HKEY subkey;
DWORD disp;
if (::RegCreateKeyEx(root, keyname, NULL, NULL, 0, KEY_WRITE, NULL,
&subkey, &disp) != ERROR_SUCCESS)
return NS_ERROR_FAILURE;
if (disp != REG_CREATED_NEW_KEY) {
::RegCloseKey(subkey);
return NS_ERROR_FAILURE;
}
PRBool failed = PR_FALSE;
failed |= ::RegSetValueEx(subkey, "Version", NULL, REG_SZ,
- (BYTE*) GRE_BUILD_ID,
- sizeof(GRE_BUILD_ID) - 1) != ERROR_SUCCESS;
+ (BYTE*) aGREMilestone,
+ strlen(aGREMilestone)) != ERROR_SUCCESS;
failed |= ::RegSetValueEx(subkey, "GreHome", NULL, REG_SZ,
(BYTE*) grehome.get(),
grehome.Length()) != ERROR_SUCCESS;
for (PRUint32 i = 0; i < aPropertiesLen; ++i) {
failed |= ::RegSetValueEx(subkey, aProperties[i].property, NULL, REG_SZ,
(BYTE*) aProperties[i].value,
strlen(aProperties[i].value)) != ERROR_SUCCESS;
@@ -92,17 +92,18 @@ MakeVersionKey(HKEY root, const char* ke
return NS_ERROR_FAILURE;
}
return NS_OK;
}
int
RegisterXULRunner(PRBool aRegisterGlobally, nsIFile* aLocation,
- const GREProperty *aProperties, PRUint32 aPropertiesLen)
+ const GREProperty *aProperties, PRUint32 aPropertiesLen,
+ const char *aGREMilestone)
{
// Register ourself in the windows registry, and record what key we created
// for future unregistration.
nsresult rv;
PRBool irv;
int i;
@@ -166,28 +167,30 @@ RegisterXULRunner(PRBool aRegisterGlobal
rv = localSaved->OpenNSPRFileDesc(PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, 0664, &fd);
if (NS_FAILED(rv)) {
// XXX report error?
irv = PR_FALSE;
goto reg_end;
}
}
- strcpy(keyName, GRE_BUILD_ID);
- rv = MakeVersionKey(rootKey, keyName, greHome, aProperties, aPropertiesLen);
+ strcpy(keyName, aGREMilestone);
+ rv = MakeVersionKey(rootKey, keyName, greHome, aProperties, aPropertiesLen,
+ aGREMilestone);
if (NS_SUCCEEDED(rv)) {
PR_Write(fd, keyName, strlen(keyName));
irv = PR_TRUE;
goto reg_end;
}
for (i = 0; i < 1000; ++i) {
- sprintf(keyName, GRE_BUILD_ID "_%i", i);
+ sprintf(keyName, "%s_%i", aGREMilestone, i);
rv = MakeVersionKey(rootKey, keyName, greHome,
- aProperties, aPropertiesLen);
+ aProperties, aPropertiesLen,
+ aGREMilestone);
if (NS_SUCCEEDED(rv)) {
PR_Write(fd, keyName, strlen(keyName));
irv = PR_TRUE;
goto reg_end;
}
}
irv = PR_FALSE;
@@ -198,17 +201,18 @@ reg_end:
if (rootKey)
::RegCloseKey(rootKey);
return irv;
}
void
-UnregisterXULRunner(PRBool aGlobal, nsIFile* aLocation)
+UnregisterXULRunner(PRBool aGlobal, nsIFile* aLocation,
+ const char *aGREMilestone)
{
nsCOMPtr<nsIFile> savedInfoFile;
aLocation->Clone(getter_AddRefs(savedInfoFile));
nsCOMPtr<nsILocalFile> localSaved (do_QueryInterface(savedInfoFile));
if (!localSaved)
return;
const char *infoname = aGlobal ? kRegFileGlobal : kRegFileUser;
--- a/xulrunner/app/nsXULRunnerApp.cpp
+++ b/xulrunner/app/nsXULRunnerApp.cpp
@@ -45,22 +45,22 @@
#include "nsXPCOMGlue.h"
#include "nsRegisterGRE.h"
#include "nsAppRunner.h"
#include "nsILocalFile.h"
#include "nsIXULAppInstall.h"
#include "nsCOMPtr.h"
#include "nsMemory.h"
#include "nsCRTGlue.h"
-#include "nsBuildID.h"
#include "nsStringAPI.h"
#include "nsServiceManagerUtils.h"
#include "plstr.h"
#include "prprf.h"
#include "prenv.h"
+#include "nsINIParser.h"
/**
* Output a string to the user. This method is really only meant to be used to
* output last-ditch error messages designed for developers NOT END USERS.
*
* @param isError
* Pass true to indicate severe errors.
* @param fmt
@@ -105,18 +105,56 @@ static PRBool IsArg(const char* arg, con
#if defined(XP_WIN) || defined(XP_OS2)
if (*arg == '/')
return !PL_strcasecmp(++arg, s);
#endif
return PR_FALSE;
}
-static void Usage()
+static nsresult
+GetGREVersion(const char *argv0,
+ nsACString *aMilestone,
+ nsACString *aVersion)
{
+ if (aMilestone)
+ aMilestone->Assign("<Error>");
+ if (aVersion)
+ aVersion->Assign("<Error>");
+
+ nsCOMPtr<nsILocalFile> iniFile;
+ nsresult rv = XRE_GetBinaryPath(argv0, getter_AddRefs(iniFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ iniFile->SetNativeLeafName(NS_LITERAL_CSTRING("platform.ini"));
+
+ nsINIParser parser;
+ rv = parser.Init(iniFile);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (aMilestone) {
+ rv = parser.GetString("Build", "Milestone", *aMilestone);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+ if (aVersion) {
+ rv = parser.GetString("Build", "BuildID", *aVersion);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+ return NS_OK;
+}
+
+static void Usage(const char *argv0)
+{
+ nsCAutoString milestone;
+ GetGREVersion(argv0, &milestone, nsnull);
+
// display additional information (XXX make localizable?)
Output(PR_FALSE,
"Mozilla XULRunner %s\n\n"
"Usage: " XULRUNNER_PROGNAME " [OPTIONS]\n"
" " XULRUNNER_PROGNAME " APP-FILE [APP-OPTIONS...]\n"
"\n"
"OPTIONS\n"
" --app specify APP-FILE (optional)\n"
@@ -134,17 +172,17 @@ static void Usage()
" --install-app <application> [<destination> [<directoryname>]]\n"
" Install a XUL application.\n"
"\n"
"APP-FILE\n"
" Application initialization file.\n"
"\n"
"APP-OPTIONS\n"
" Application specific options.\n",
- GRE_BUILD_ID);
+ milestone.get());
}
static nsresult
GetXULRunnerDir(const char *argv0, nsIFile* *aResult)
{
nsresult rv;
nsCOMPtr<nsILocalFile> appFile;
@@ -237,99 +275,110 @@ private:
};
int main(int argc, char* argv[])
{
if (argc > 1 && (IsArg(argv[1], "h") ||
IsArg(argv[1], "help") ||
IsArg(argv[1], "?")))
{
- Usage();
+ Usage(argv[0]);
return 0;
}
if (argc == 2 && (IsArg(argv[1], "v") || IsArg(argv[1], "version")))
{
- Output(PR_FALSE, "Mozilla XULRunner %s\n", GRE_BUILD_ID);
+ nsCAutoString milestone;
+ nsCAutoString version;
+ GetGREVersion(argv[0], &milestone, &version);
+ Output(PR_FALSE, "Mozilla XULRunner %s - %s\n",
+ milestone.get(), version.get());
return 0;
}
if (argc > 1) {
+ nsCAutoString milestone;
+ nsresult rv = GetGREVersion(argv[0], &milestone, nsnull);
+ if (NS_FAILED(rv))
+ return 2;
+
PRBool registerGlobal = IsArg(argv[1], "register-global");
PRBool registerUser = IsArg(argv[1], "register-user");
if (registerGlobal || registerUser) {
if (argc != 2) {
- Usage();
+ Usage(argv[0]);
return 1;
}
nsCOMPtr<nsIFile> regDir;
- nsresult rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
+ rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
if (NS_FAILED(rv))
return 2;
return RegisterXULRunner(registerGlobal, regDir,
kGREProperties,
- NS_ARRAY_LENGTH(kGREProperties)) ? 0 : 2;
+ NS_ARRAY_LENGTH(kGREProperties),
+ milestone.get()) ? 0 : 2;
}
registerGlobal = IsArg(argv[1], "unregister-global");
registerUser = IsArg(argv[1], "unregister-user");
if (registerGlobal || registerUser) {
if (argc != 2) {
- Usage();
+ Usage(argv[0]);
return 1;
}
nsCOMPtr<nsIFile> regDir;
- nsresult rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
+ rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
if (NS_FAILED(rv))
return 2;
- UnregisterXULRunner(registerGlobal, regDir);
+
+ UnregisterXULRunner(registerGlobal, regDir, milestone.get());
return 0;
}
if (IsArg(argv[1], "find-gre")) {
if (argc != 3) {
- Usage();
+ Usage(argv[0]);
return 1;
}
char path[MAXPATHLEN];
static const GREVersionRange vr = {
argv[2], PR_TRUE,
argv[2], PR_TRUE
};
static const GREProperty kProperties[] = {
{ "xulrunner", "true" }
};
- nsresult rv = GRE_GetGREPathWithProperties(&vr, 1, kProperties,
- NS_ARRAY_LENGTH(kProperties),
- path, sizeof(path));
+ rv = GRE_GetGREPathWithProperties(&vr, 1, kProperties,
+ NS_ARRAY_LENGTH(kProperties),
+ path, sizeof(path));
if (NS_FAILED(rv))
return 1;
printf("%s\n", path);
return 0;
}
if (IsArg(argv[1], "gre-version")) {
if (argc != 2) {
- Usage();
+ Usage(argv[0]);
return 1;
}
- printf("%s\n", GRE_BUILD_ID);
+ printf("%s\n", milestone.get());
return 0;
}
if (IsArg(argv[1], "install-app")) {
if (argc < 3 || argc > 5) {
- Usage();
+ Usage(argv[0]);
return 1;
}
char *appLocation = argv[2];
char *installTo = nsnull;
if (argc > 3) {
installTo = argv[3];
@@ -340,35 +389,35 @@ int main(int argc, char* argv[])
char *leafName = nsnull;
if (argc > 4) {
leafName = argv[4];
if (!*leafName)
leafName = nsnull;
}
nsCOMPtr<nsIFile> regDir;
- nsresult rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
+ rv = GetXULRunnerDir(argv[0], getter_AddRefs(regDir));
if (NS_FAILED(rv))
return 2;
return InstallXULApp(regDir, appLocation, installTo, leafName);
}
}
const char *appDataFile = PR_GetEnv("XUL_APP_FILE");
if (!(appDataFile && *appDataFile)) {
if (argc < 2) {
- Usage();
+ Usage(argv[0]);
return 1;
}
if (IsArg(argv[1], "app")) {
if (argc == 2) {
- Usage();
+ Usage(argv[0]);
return 1;
}
argv[1] = argv[0];
++argv;
--argc;
}
appDataFile = argv[1];
--- a/xulrunner/examples/simple/application.ini
+++ b/xulrunner/examples/simple/application.ini
@@ -8,17 +8,17 @@ Vendor=MozillaTest
; This field specifies your application's name. This field is required.
Name=Simple
;
; This field specifies your application's version. This field is required.
Version=0.1
;
; This field specifies your application's build ID (timestamp). This field is
; required.
-BuildID=@BUILD_ID@
+BuildID=20070625
;
; This field specifies a compact copyright notice for your application. This
; field is optional.
Copyright=Copyright (c) 2004 Mozilla.org
;
; This ID is just an example. Every XUL app ought to have it's own unique ID.
; You can use the microsoft "guidgen" or "uuidgen" tools, or go on
; irc.mozilla.org and /msg botbot uuid. This field is optional.