зеркало из https://github.com/mozilla/pluotsorbet.git
merge
This commit is contained in:
Коммит
d3d7dc68cf
|
@ -7,6 +7,12 @@ certs/j2se_test.ks
|
||||||
tests/Testlets.java
|
tests/Testlets.java
|
||||||
output/
|
output/
|
||||||
build/
|
build/
|
||||||
|
.checksum
|
||||||
|
|
||||||
|
# These are generated by the python preprocessor. They're generated from
|
||||||
|
# the *.in files.
|
||||||
|
config.ts
|
||||||
|
main.html
|
||||||
config/build.js
|
config/build.js
|
||||||
|
|
||||||
# These are generated by the Java pre-processor. They're generated from
|
# These are generated by the Java pre-processor. They're generated from
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -1,15 +1,35 @@
|
||||||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build relooper
|
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build
|
||||||
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*")
|
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*") config.ts
|
||||||
JIT_SRCS=$(shell find jit -name "*.ts" -not -path "./build/*")
|
JIT_SRCS=$(shell find jit -name "*.ts" -not -path "./build/*")
|
||||||
SHUMWAY_SRCS=$(shell find shumway -name "*.ts")
|
SHUMWAY_SRCS=$(shell find shumway -name "*.ts")
|
||||||
RELEASE ?= 0
|
RELEASE ?= 0
|
||||||
VERSION ?=$(shell date +%s)
|
VERSION ?=$(shell date +%s)
|
||||||
|
PROFILE ?= 0
|
||||||
|
|
||||||
|
# Create a checksum file to monitor the changes of the Makefile configuration.
|
||||||
|
# If the configuration has changed, we update the checksum file to let the files
|
||||||
|
# which depend on it to regenerate.
|
||||||
|
|
||||||
|
CHECKSUM := "$(RELEASE)$(PROFILE)"
|
||||||
|
OLD_CHECKSUM := "$(shell [ -f .checksum ] && cat .checksum)"
|
||||||
|
$(shell [ $(CHECKSUM) != $(OLD_CHECKSUM) ] && echo $(CHECKSUM) > .checksum)
|
||||||
|
|
||||||
|
toBool = $(if $(findstring 1,$(1)),true,false)
|
||||||
|
PREPROCESS = python tools/preprocess-1.1.0/lib/preprocess.py -s \
|
||||||
|
-D RELEASE=$(call toBool,$(RELEASE)) \
|
||||||
|
-D PROFILE=$(call toBool,$(PROFILE)) \
|
||||||
|
-D VERSION=$(VERSION)
|
||||||
|
PREPROCESS_SRCS = $(shell find . -name "*.in" -not -path config/build.js.in)
|
||||||
|
PREPROCESS_DESTS = $(PREPROCESS_SRCS:.in=)
|
||||||
|
|
||||||
all: config-build java jasmin tests j2me shumway aot
|
all: config-build java jasmin tests j2me shumway aot
|
||||||
|
|
||||||
test: all
|
test: all
|
||||||
tests/runtests.py
|
tests/runtests.py
|
||||||
|
|
||||||
|
$(PREPROCESS_DESTS): $(PREPROCESS_SRCS) .checksum
|
||||||
|
$(foreach file,$(PREPROCESS_SRCS),$(PREPROCESS) -o $(file:.in=) $(file);)
|
||||||
|
|
||||||
jasmin:
|
jasmin:
|
||||||
make -C tools/jasmin-2.4
|
make -C tools/jasmin-2.4
|
||||||
|
|
||||||
|
@ -51,10 +71,10 @@ shumway: build/shumway.js
|
||||||
build/shumway.js: $(SHUMWAY_SRCS)
|
build/shumway.js: $(SHUMWAY_SRCS)
|
||||||
node tools/tsc.js --sourcemap --target ES5 shumway/references.ts --out build/shumway.js
|
node tools/tsc.js --sourcemap --target ES5 shumway/references.ts --out build/shumway.js
|
||||||
|
|
||||||
config-build:
|
# We should update config/build.js everytime to generate the new VERSION number
|
||||||
echo "// generated, build-specific configuration" > config/build.js
|
# based on current time.
|
||||||
echo "config.release = ${RELEASE};" >> config/build.js
|
config-build: config/build.js.in
|
||||||
echo "config.version = \"${VERSION}\";" >> config/build.js
|
$(PREPROCESS) -o config/build.js config/build.js.in
|
||||||
|
|
||||||
tests/tests.jar: tests
|
tests/tests.jar: tests
|
||||||
tests:
|
tests:
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @const */ var release: boolean = @RELEASE@;
|
||||||
|
/** @const */ var profile: boolean = @PROFILE@;
|
|
@ -0,0 +1,4 @@
|
||||||
|
// generated, build-specific configuration
|
||||||
|
|
||||||
|
config.release = @RELEASE@;
|
||||||
|
config.version = "@VERSION@";
|
|
@ -11,7 +11,7 @@ classes.jar: $(SRCS) $(JPP_DESTS)
|
||||||
mkdir build build-src
|
mkdir build build-src
|
||||||
cp -a cldc1.1.1/. vm/. midp/. jsr-075/. build-src/
|
cp -a cldc1.1.1/. vm/. midp/. jsr-075/. build-src/
|
||||||
cp -a custom/. build-src/
|
cp -a custom/. build-src/
|
||||||
javac -cp build-src -source 1.3 -target 1.3 -bootclasspath "" -extdirs "" -d ./build `find ./build-src -name *.java` > /dev/null
|
javac -cp build-src -g:none -source 1.3 -target 1.3 -bootclasspath "" -extdirs "" -d ./build `find ./build-src -name *.java` > /dev/null
|
||||||
cd build && jar cvf0 ../classes.jar *
|
cd build && jar cvf0 ../classes.jar *
|
||||||
jar uvf0 classes.jar $(EXTRA)
|
jar uvf0 classes.jar $(EXTRA)
|
||||||
rm -rf build build-src
|
rm -rf build build-src
|
||||||
|
|
|
@ -3,6 +3,9 @@ package com.nokia.mid.s40.bg;
|
||||||
import com.sun.midp.main.MIDletSuiteUtils;
|
import com.sun.midp.main.MIDletSuiteUtils;
|
||||||
|
|
||||||
class WaitUserInteractionThread extends Thread {
|
class WaitUserInteractionThread extends Thread {
|
||||||
|
public WaitUserInteractionThread() {
|
||||||
|
setPriority(Thread.MAX_PRIORITY);
|
||||||
|
}
|
||||||
public void run() {
|
public void run() {
|
||||||
BGUtils.waitUserInteraction();
|
BGUtils.waitUserInteraction();
|
||||||
BGUtils.startMIDlet();
|
BGUtils.startMIDlet();
|
||||||
|
|
|
@ -14,8 +14,9 @@
|
||||||
<script type="text/javascript" src="config/midlet.js" defer></script>
|
<script type="text/javascript" src="config/midlet.js" defer></script>
|
||||||
<script type="text/javascript" src="config/build.js" defer></script>
|
<script type="text/javascript" src="config/build.js" defer></script>
|
||||||
<script type="text/javascript" src="config/urlparams.js" defer></script>
|
<script type="text/javascript" src="config/urlparams.js" defer></script>
|
||||||
<!-- Uncomment the line below to enable the profiler. -->
|
<!-- #if PROFILE == "true" -->
|
||||||
<!--<script type="text/javascript" src="build/shumway.js" defer></script>-->
|
<script type="text/javascript" src="build/shumway.js" defer></script>
|
||||||
|
<!-- #endif -->
|
||||||
<!--<script type="text/javascript" src="libs/terminal.js" defer></script>-->
|
<!--<script type="text/javascript" src="libs/terminal.js" defer></script>-->
|
||||||
<script type="text/javascript" src="libs/console.js" defer></script>
|
<script type="text/javascript" src="libs/console.js" defer></script>
|
||||||
<script type="text/javascript" src="libs/promise-6.0.0.js" defer></script>
|
<script type="text/javascript" src="libs/promise-6.0.0.js" defer></script>
|
|
@ -1,4 +1,5 @@
|
||||||
// Basics
|
// Basics
|
||||||
|
///<reference path='config.ts' />
|
||||||
///<reference path='utilities.ts' />
|
///<reference path='utilities.ts' />
|
||||||
|
|
||||||
///<reference path='classfile/classfile.ts' />
|
///<reference path='classfile/classfile.ts' />
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Basics
|
// Basics
|
||||||
|
|
||||||
|
///<reference path='config.ts' />
|
||||||
///<reference path='utilities.ts' />
|
///<reference path='utilities.ts' />
|
||||||
|
|
||||||
///<reference path='classfile/classfile.ts' />
|
///<reference path='classfile/classfile.ts' />
|
||||||
|
|
23
runtime.ts
23
runtime.ts
|
@ -1170,16 +1170,31 @@ module J2ME {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reportError(method, key) {
|
||||||
|
return function() {
|
||||||
|
try {
|
||||||
|
return method.apply(this, arguments);
|
||||||
|
} catch (e) {
|
||||||
|
// Filter JAVA exception and only report the native js exception, which
|
||||||
|
// cannnot be handled properly by the JAVA code.
|
||||||
|
if (!e.klass) {
|
||||||
|
stderrWriter.errorLn("Native " + key + " throws: " + e);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function findNativeMethodImplementation(methodInfo: MethodInfo) {
|
function findNativeMethodImplementation(methodInfo: MethodInfo) {
|
||||||
|
var implKey = methodInfo.implKey;
|
||||||
// Look in bindings first.
|
// Look in bindings first.
|
||||||
var binding = findNativeMethodBinding(methodInfo);
|
var binding = findNativeMethodBinding(methodInfo);
|
||||||
if (binding) {
|
if (binding) {
|
||||||
return binding;
|
return release ? binding : reportError(binding, implKey);
|
||||||
}
|
}
|
||||||
var implKey = methodInfo.implKey;
|
|
||||||
if (methodInfo.isNative) {
|
if (methodInfo.isNative) {
|
||||||
if (implKey in Native) {
|
if (implKey in Native) {
|
||||||
return Native[implKey];
|
return release ? Native[implKey] : reportError(Native[implKey], implKey);
|
||||||
} else {
|
} else {
|
||||||
// Some Native MethodInfos are constructed but never called;
|
// Some Native MethodInfos are constructed but never called;
|
||||||
// that's fine, unless we actually try to call them.
|
// that's fine, unless we actually try to call them.
|
||||||
|
@ -1188,7 +1203,7 @@ module J2ME {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (implKey in Override) {
|
} else if (implKey in Override) {
|
||||||
return Override[implKey];
|
return release ? Override[implKey] : reportError(Override[implKey], implKey);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ mkdir $PACKAGE_DIR/build
|
||||||
# setup the root
|
# setup the root
|
||||||
cp *.js *.html *.webapp $PACKAGE_DIR/.
|
cp *.js *.html *.webapp $PACKAGE_DIR/.
|
||||||
cp build/j2me.js $PACKAGE_DIR/build/.
|
cp build/j2me.js $PACKAGE_DIR/build/.
|
||||||
|
cp build/classes.jar.js $PACKAGE_DIR/build/.
|
||||||
|
|
||||||
# copy over jars/jads that are used for the webapp
|
# copy over jars/jads that are used for the webapp
|
||||||
# NB: we could be smart about this and parse the manifest, patches welcome!
|
# NB: we could be smart about this and parse the manifest, patches welcome!
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright (c) 2002-2005 ActiveState Corp.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
|
@ -0,0 +1,420 @@
|
||||||
|
preprocess.py -- a portable multi-language file preprocessor
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
Download the latest preprocess.py packages from here:
|
||||||
|
(archive) http://preprocess.googlecode.com/files/preprocess-1.1.0.zip
|
||||||
|
|
||||||
|
|
||||||
|
Home : http://trentm.com/projects/preprocess/
|
||||||
|
License : MIT (see LICENSE.txt)
|
||||||
|
Platforms : Windows, Linux, Mac OS X, Unix
|
||||||
|
Current Version : 1.1
|
||||||
|
Dev Status : Fairly mature, has been used in the Komodo build system for
|
||||||
|
over 7 years.
|
||||||
|
Requirements : Python >= 2.3 (http://www.activestate.com/ActivePython/)
|
||||||
|
|
||||||
|
|
||||||
|
What's new?
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Support has been added for preprocessing TeX, Fortran, C#, Java, Shell
|
||||||
|
script and PHP files. See the [Change Log](#changelog) below for more.
|
||||||
|
|
||||||
|
|
||||||
|
Why preprocess.py?
|
||||||
|
------------------
|
||||||
|
|
||||||
|
There are millions of templating systems out there (most of them
|
||||||
|
developed for the web). This isn't one of those, though it does share
|
||||||
|
some basics: a markup syntax for templates that are processed to give
|
||||||
|
resultant text output. The main difference with `preprocess.py` is
|
||||||
|
that its syntax is hidden in comments (whatever the syntax for comments
|
||||||
|
maybe in the target filetype) so that the file can still have valid
|
||||||
|
syntax. A comparison with the C preprocessor is more apt.
|
||||||
|
|
||||||
|
`preprocess.py` is targetted at build systems that deal with many
|
||||||
|
types of files. Languages for which it works include: C++, Python,
|
||||||
|
Perl, Tcl, XML, JavaScript, CSS, IDL, TeX, Fortran, PHP, Java, Shell
|
||||||
|
scripts (Bash, CSH, etc.) and C#. Preprocess is usable both as a
|
||||||
|
command line app and as a Python module.
|
||||||
|
|
||||||
|
Here is how is works: All preprocessor statements are on their own
|
||||||
|
line. A preprocessor statement is a comment (as appropriate for the
|
||||||
|
language of the file being preprocessed). This way the preprocessor
|
||||||
|
statements do not make an unpreprocessed file syntactically incorrect.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
preprocess -D FEATURES=macros,scc myapp.py
|
||||||
|
|
||||||
|
will yield this transformation:
|
||||||
|
|
||||||
|
... ...
|
||||||
|
# #if "macros" in FEATURES
|
||||||
|
def do_work_with_macros(): def do_work_with_macros():
|
||||||
|
pass pass
|
||||||
|
# #else
|
||||||
|
def do_work_without_macros():
|
||||||
|
pass
|
||||||
|
# #endif
|
||||||
|
... ...
|
||||||
|
|
||||||
|
or, with a JavaScript file:
|
||||||
|
|
||||||
|
... ...
|
||||||
|
// #if "macros" in FEATURES
|
||||||
|
function do_work_with_macros() { function do_work_with_macros() {
|
||||||
|
} }
|
||||||
|
// #else
|
||||||
|
function do_work_without_macros() {
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
... ...
|
||||||
|
|
||||||
|
Despite these contrived examples preprocess has proved useful for
|
||||||
|
build-time code differentiation in the
|
||||||
|
[Komodo](http://www.activestate.com/Komodo) build system -- which
|
||||||
|
includes source code in Python, JavaScript, XML, CSS, Perl, and C/C++.
|
||||||
|
|
||||||
|
The #if expression (`"macros" in FEATURES` in the example) is Python
|
||||||
|
code, so has Python's full comparison richness. A number of
|
||||||
|
preprocessor statements are implemented:
|
||||||
|
|
||||||
|
#define VAR [VALUE]
|
||||||
|
#undef VAR
|
||||||
|
#ifdef VAR
|
||||||
|
#ifndef VAR
|
||||||
|
#if EXPRESSION
|
||||||
|
#elif EXPRESSION
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
#error ERROR_STRING
|
||||||
|
#include "FILE"
|
||||||
|
@varName@
|
||||||
|
|
||||||
|
As well, preprocess will do in-line substitution of defined variables.
|
||||||
|
Although this is currently off by default because substitution will occur
|
||||||
|
in program strings, which is not ideal. When a future version of
|
||||||
|
preprocess can lex languages being preprocessed it will NOT substitute
|
||||||
|
into program strings and substitution will be turned ON by default.
|
||||||
|
|
||||||
|
A workaround is made to resolve this issue. Variables embraced by @ will be
|
||||||
|
substitute by its value in the emitted lines. For example if we define
|
||||||
|
NAME="Yuan Xulei", the input file:
|
||||||
|
<p>Hello I'm @NAME@!</p>
|
||||||
|
will output:
|
||||||
|
<p>Hello I'm Yuan Xulei!</p>
|
||||||
|
|
||||||
|
Please send any feedback to [Trent Mick](mailto:trentm@google's mail
|
||||||
|
thing.com).
|
||||||
|
|
||||||
|
|
||||||
|
Install Notes
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Download the latest `preprocess` source package, unzip it, and run `python
|
||||||
|
setup.py install`:
|
||||||
|
|
||||||
|
unzip preprocess-1.1.0.zip
|
||||||
|
cd preprocess-1.1.0
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
If your install fails then please visit [the Troubleshooting
|
||||||
|
FAQ](http://trentm.com/faq.html#troubleshooting-python-package-installation).
|
||||||
|
|
||||||
|
This will install `preprocess.py` into your Python `site-packages` and
|
||||||
|
also into your Python bin directory. If you can now run `preprocess`
|
||||||
|
and get a response then you are good to go, otherwise read on.
|
||||||
|
|
||||||
|
The *problem* is that the Python bin directory is not always on your
|
||||||
|
PATH on some operating systems -- notably Mac OS X. To finish the
|
||||||
|
install on OS X either manually move 'preprocess' to somewhere on your
|
||||||
|
PATH:
|
||||||
|
|
||||||
|
cp preprocess.py /usr/local/bin/preprocess
|
||||||
|
|
||||||
|
or create a symlink to it (try one of these depending on your Python
|
||||||
|
version):
|
||||||
|
|
||||||
|
ln -s /System/Library/Frameworks/Python.framework/Versions/2.3/bin/preprocess /usr/local/bin/preprocess
|
||||||
|
ln -s /Library/Frameworks/Python.framework/Versions/2.4/bin/preprocess /usr/local/bin/preprocess
|
||||||
|
|
||||||
|
(Note: You'll probably need to prefix those commands with `sudo` and
|
||||||
|
the exact paths may differ on your system.)
|
||||||
|
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Once you have it install, run `preprocess --help` for full usage
|
||||||
|
information:
|
||||||
|
|
||||||
|
$ preprocess --help
|
||||||
|
Preprocess a file.
|
||||||
|
|
||||||
|
Command Line Usage:
|
||||||
|
preprocess [<options>...] <infile>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this help and exit.
|
||||||
|
-V, --version Print the version info and exit.
|
||||||
|
-v, --verbose Give verbose output for errors.
|
||||||
|
|
||||||
|
-o <outfile> Write output to the given file instead of to stdout.
|
||||||
|
-f, --force Overwrite given output file. (Otherwise an IOError
|
||||||
|
will be raised if <outfile> already exists.
|
||||||
|
-D <define> Define a variable for preprocessing. <define>
|
||||||
|
can simply be a variable name (in which case it
|
||||||
|
will be true) or it can be of the form
|
||||||
|
<var>=<val>. An attempt will be made to convert
|
||||||
|
<val> to an integer so "-D FOO=0" will create a
|
||||||
|
false value.
|
||||||
|
-I <dir> Add an directory to the include path for
|
||||||
|
#include directives.
|
||||||
|
|
||||||
|
-k, --keep-lines Emit empty lines for preprocessor statement
|
||||||
|
lines and skipped output lines. This allows line
|
||||||
|
numbers to stay constant.
|
||||||
|
-s, --substitute Substitute defines into emitted lines. By
|
||||||
|
default substitution is NOT done because it
|
||||||
|
currently will substitute into program strings.
|
||||||
|
|
||||||
|
Module Usage:
|
||||||
|
from preprocess import preprocess
|
||||||
|
preprocess(infile, outfile=sys.stdout, defines={}, force=0,
|
||||||
|
keepLines=0, includePath=[], substitute=0)
|
||||||
|
|
||||||
|
The <infile> can be marked up with special preprocessor statement lines
|
||||||
|
of the form:
|
||||||
|
<comment-prefix> <preprocessor-statement> <comment-suffix>
|
||||||
|
where the <comment-prefix/suffix> are the native comment delimiters for
|
||||||
|
that file type.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
HTML (*.htm, *.html) or XML (*.xml, *.kpf, *.xul) files:
|
||||||
|
|
||||||
|
<!-- #if FOO -->
|
||||||
|
...
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
Python (*.py), Perl (*.pl), Tcl (*.tcl), Ruby (*.rb), Bash (*.sh),
|
||||||
|
or make ([Mm]akefile*) files:
|
||||||
|
|
||||||
|
# #if defined('FAV_COLOR') and FAV_COLOR == "blue"
|
||||||
|
...
|
||||||
|
# #elif FAV_COLOR == "red"
|
||||||
|
...
|
||||||
|
# #else
|
||||||
|
...
|
||||||
|
# #endif
|
||||||
|
|
||||||
|
C (*.c, *.h), C++ (*.cpp, *.cxx, *.cc, *.h, *.hpp, *.hxx, *.hh),
|
||||||
|
Java (*.java), PHP (*.php) or C# (*.cs) files:
|
||||||
|
|
||||||
|
// #define FAV_COLOR 'blue'
|
||||||
|
...
|
||||||
|
/* #ifndef FAV_COLOR */
|
||||||
|
...
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
Fortran 77 (*.f) or 90/95 (*.f90) files:
|
||||||
|
|
||||||
|
C #if COEFF == 'var'
|
||||||
|
...
|
||||||
|
C #endif
|
||||||
|
|
||||||
|
|
||||||
|
Preprocessor Syntax
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Valid statements:
|
||||||
|
#define <var> [<value>]
|
||||||
|
#undef <var>
|
||||||
|
#ifdef <var>
|
||||||
|
#ifndef <var>
|
||||||
|
#if <expr>
|
||||||
|
#elif <expr>
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
#error <error string>
|
||||||
|
#include "<file>"
|
||||||
|
where <expr> is any valid Python expression.
|
||||||
|
- The expression after #if/elif may be a Python statement. It is an
|
||||||
|
error to refer to a variable that has not been defined by a -D
|
||||||
|
option or by an in-content #define.
|
||||||
|
- Special built-in methods for expressions:
|
||||||
|
defined(varName) Return true if given variable is defined.
|
||||||
|
|
||||||
|
|
||||||
|
Tips
|
||||||
|
----
|
||||||
|
|
||||||
|
A suggested file naming convention is to let input files to
|
||||||
|
preprocess be of the form <basename>.p.<ext> and direct the output
|
||||||
|
of preprocess to <basename>.<ext>, e.g.:
|
||||||
|
preprocess -o foo.py foo.p.py
|
||||||
|
The advantage is that other tools (esp. editors) will still
|
||||||
|
recognize the unpreprocessed file as the original language.
|
||||||
|
|
||||||
|
|
||||||
|
And, for module usage, read the preprocess.preprocess() docstring:
|
||||||
|
|
||||||
|
pydoc preprocess.preprocess
|
||||||
|
|
||||||
|
|
||||||
|
Change Log
|
||||||
|
----------
|
||||||
|
|
||||||
|
### v1.1.0
|
||||||
|
- Move to code.google.com/p/preprocess for code hosting.
|
||||||
|
- Re-org directory structure to assist with deployment to pypi and
|
||||||
|
better installation with setup.py.
|
||||||
|
- Pulled the "content.types" file that assists with filetype
|
||||||
|
determination into "preprocess.py". This makes "preprocess.py" fully
|
||||||
|
independent and also makes the "setup.py" simpler. The
|
||||||
|
"-c|--content-types-path" option can be used to specify
|
||||||
|
addition content types information.
|
||||||
|
|
||||||
|
### v1.0.9
|
||||||
|
- Fix the 'contentType' optional arg for #include's.
|
||||||
|
- Add cheap XML content sniffing.
|
||||||
|
|
||||||
|
### v1.0.8
|
||||||
|
- Allow for JS and CSS-style comment delims in XML/HTML. Ideally this
|
||||||
|
would deal with full lexing but that isn't going to happen soon.
|
||||||
|
|
||||||
|
### v1.0.7
|
||||||
|
- Allow explicit specification of content type.
|
||||||
|
### v1.0.6
|
||||||
|
- Add ability to include a filename mentioned in a define: '#include
|
||||||
|
VAR'.
|
||||||
|
|
||||||
|
|
||||||
|
### v1.0.5
|
||||||
|
- Make sure to use the *longest* define names first when doing
|
||||||
|
substitutions. This ensure that substitution in this line:
|
||||||
|
FOO and BAR are FOOBAR
|
||||||
|
will do the right thing if there are "FOO" and "FOOBAR" defines.
|
||||||
|
|
||||||
|
### v1.0.4
|
||||||
|
- Add WiX XML file extensions.
|
||||||
|
- Add XSLT file extensions.
|
||||||
|
|
||||||
|
### v1.0.3
|
||||||
|
- TeX support (from Hans Petter Langtangen)
|
||||||
|
|
||||||
|
### v1.0.2
|
||||||
|
- Fix a bug with -k|--keep-lines and preprocessor some directives in
|
||||||
|
ignored if blocks (undef, define, error, include): those lines were
|
||||||
|
not kept. (bug noted by Eric Promislow)
|
||||||
|
|
||||||
|
### v1.0.1
|
||||||
|
- Fix documentation error for '#define' statement. The correct syntax
|
||||||
|
is '#define VAR [VALUE]' while the docs used to say
|
||||||
|
'#define VAR[=VALUE]'. (from Hans Petter Langtangen)
|
||||||
|
- Correct '! ...' comment-style for Fortran -- the '!' can be on any
|
||||||
|
column in Fortran 90. (from Hans Petter Langtangen)
|
||||||
|
- Return a non-zero exit code on error.
|
||||||
|
|
||||||
|
### v1.0.0
|
||||||
|
- Update the test suite (it had been broken for quite a while) and add
|
||||||
|
a Fortran test case.
|
||||||
|
- Improve Fortran support to support any char in the first column to
|
||||||
|
indicate a comment. (Idea from Hans Petter Langtangen)
|
||||||
|
- Recognize '.f90' files as Fortran. (from Hans Petter Langtangen)
|
||||||
|
- Add Java, C#, Shell script and PHP support. (from Hans Petter
|
||||||
|
Langtangen)
|
||||||
|
|
||||||
|
### v0.9.2
|
||||||
|
- Add Fortran support (from Hans Petter Langtangen)
|
||||||
|
- Ensure content.types gets written to "bindir" next to preprocess.py
|
||||||
|
there so it can be picked up (from Hans Petter Langtangen).
|
||||||
|
|
||||||
|
### v0.9.1
|
||||||
|
- Fully read in the input file before processing. This allows
|
||||||
|
preprocessing of a file onto itself.
|
||||||
|
|
||||||
|
### v0.9.0
|
||||||
|
- Change version attributes and semantics. Before: had a _version_
|
||||||
|
tuple. After: __version__ is a string, __version_info__ is a tuple.
|
||||||
|
|
||||||
|
### v0.8.1
|
||||||
|
- Mentioned #ifdef and #ifndef in documentation (these have been there
|
||||||
|
for a while).
|
||||||
|
- Add preprocess.exe to source package (should fix installation on
|
||||||
|
Windows).
|
||||||
|
- Incorporate Komodo changes:
|
||||||
|
- change 171050: add Ruby support
|
||||||
|
- change 160914: Only attempt to convert define strings from the
|
||||||
|
command-line to *int* instead of eval'ing as any Python
|
||||||
|
expression: which could surprise with strings that work as
|
||||||
|
floats.
|
||||||
|
- change 67962: Fix '#include' directives in preprocessed files.
|
||||||
|
|
||||||
|
### v0.8.0
|
||||||
|
- Move hosting to trentm.com. Improve the starter docs a little bit.
|
||||||
|
|
||||||
|
### 0.7.0:
|
||||||
|
- Fix bug 1: Nested #if-blocks will not be properly handled.
|
||||||
|
- Add 'Text' type for .txt files and default (with a warn) unknown
|
||||||
|
filetypes to 'Text'. Text files are defined to use to '#...'-style
|
||||||
|
comments to allow if/else/.../endif directives as in
|
||||||
|
Perl/Python/Tcl files.
|
||||||
|
|
||||||
|
### 0.6.1:
|
||||||
|
- Fix a bug where preprocessor statements were not ignored when not
|
||||||
|
emitting. For example the following should _not_ cause an error:
|
||||||
|
# #if 0
|
||||||
|
# #error womba womba womba
|
||||||
|
# #endif
|
||||||
|
- Fix a bug where multiple uses of preprocess.preprocess() in the
|
||||||
|
same interpreter would erroneously re-use the same list of
|
||||||
|
__preprocessedFiles. This could cause false detection of recursive
|
||||||
|
#include's.
|
||||||
|
- Fix #include, broken in 0.6.0.
|
||||||
|
|
||||||
|
### 0.6.0:
|
||||||
|
- substitution: Variables can now replaced with their defined value
|
||||||
|
in preprocessed file content. This is turned OFF by default
|
||||||
|
because, IMO, substitution should not be done in program strings.
|
||||||
|
I need to add lexing for all supported languages before I can do
|
||||||
|
*that* properly. Substitution can be turned on with the
|
||||||
|
--substitute command-line option or the subst=1 module interface
|
||||||
|
option.
|
||||||
|
- Add support for preprocessing HTML files.
|
||||||
|
|
||||||
|
### 0.5.0:
|
||||||
|
- Add #error, #define, #undef, #ifdef and #ifndef statements.
|
||||||
|
- #include statement, -I command line option and 'includePath'
|
||||||
|
module interface option to specify an include path
|
||||||
|
- Add __FILE__ and __LINE__ default defines.
|
||||||
|
- More strict and more helpful error messages:
|
||||||
|
- Lines of the form "#else <expr>" and "#endif <expr>" no longer
|
||||||
|
match.
|
||||||
|
- error messages for illegal #if-block constructs
|
||||||
|
- error messages for use of defined(BAR) instead of
|
||||||
|
defined('BAR') in expressions
|
||||||
|
- New "keep lines" option to output blank lines for skipped content
|
||||||
|
lines and preprocessor statement lines (to preserve line numbers
|
||||||
|
in the processed file).
|
||||||
|
|
||||||
|
### 0.4.0:
|
||||||
|
- Add #elif preprocessor statement.
|
||||||
|
- Add defined() built-in, e.g. #if defined('FOO')
|
||||||
|
|
||||||
|
### 0.3.2:
|
||||||
|
- Make #if expressions Python code.
|
||||||
|
- Change "defines" attribute of preprocess.preprocess().
|
||||||
|
- Add -f|--force option to overwrite given output file.
|
||||||
|
|
||||||
|
### 0.2.0:
|
||||||
|
- Add content types for C/C++.
|
||||||
|
- Better module documentation.
|
||||||
|
- You can define *false* vars on the command line now.
|
||||||
|
- 'python setup.py install' works.
|
||||||
|
|
||||||
|
### 0.1.0:
|
||||||
|
- First release.
|
||||||
|
|
|
@ -0,0 +1,847 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (c) 2002-2008 ActiveState Software Inc.
|
||||||
|
# License: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Preprocess a file.
|
||||||
|
|
||||||
|
Command Line Usage:
|
||||||
|
preprocess [<options>...] <infile>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print this help and exit.
|
||||||
|
-V, --version Print the version info and exit.
|
||||||
|
-v, --verbose Give verbose output for errors.
|
||||||
|
|
||||||
|
-o <outfile> Write output to the given file instead of to stdout.
|
||||||
|
-f, --force Overwrite given output file. (Otherwise an IOError
|
||||||
|
will be raised if <outfile> already exists.
|
||||||
|
-D <define> Define a variable for preprocessing. <define>
|
||||||
|
can simply be a variable name (in which case it
|
||||||
|
will be true) or it can be of the form
|
||||||
|
<var>=<val>. An attempt will be made to convert
|
||||||
|
<val> to an integer so "-D FOO=0" will create a
|
||||||
|
false value.
|
||||||
|
-I <dir> Add an directory to the include path for
|
||||||
|
#include directives.
|
||||||
|
|
||||||
|
-k, --keep-lines Emit empty lines for preprocessor statement
|
||||||
|
lines and skipped output lines. This allows line
|
||||||
|
numbers to stay constant.
|
||||||
|
-s, --substitute Substitute defines into emitted lines. By
|
||||||
|
default substitution is NOT done because it
|
||||||
|
currently will substitute into program strings.
|
||||||
|
-c, --content-types-path <path>
|
||||||
|
Specify a path to a content.types file to assist
|
||||||
|
with filetype determination. See the
|
||||||
|
`_gDefaultContentTypes` string in this file for
|
||||||
|
details on its format.
|
||||||
|
|
||||||
|
Module Usage:
|
||||||
|
from preprocess import preprocess
|
||||||
|
preprocess(infile, outfile=sys.stdout, defines={}, force=0,
|
||||||
|
keepLines=0, includePath=[], substitute=0,
|
||||||
|
contentType=None)
|
||||||
|
|
||||||
|
The <infile> can be marked up with special preprocessor statement lines
|
||||||
|
of the form:
|
||||||
|
<comment-prefix> <preprocessor-statement> <comment-suffix>
|
||||||
|
where the <comment-prefix/suffix> are the native comment delimiters for
|
||||||
|
that file type.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
HTML (*.htm, *.html) or XML (*.xml, *.kpf, *.xul) files:
|
||||||
|
|
||||||
|
<!-- #if FOO -->
|
||||||
|
...
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
Python (*.py), Perl (*.pl), Tcl (*.tcl), Ruby (*.rb), Bash (*.sh),
|
||||||
|
or make ([Mm]akefile*) files:
|
||||||
|
|
||||||
|
# #if defined('FAV_COLOR') and FAV_COLOR == "blue"
|
||||||
|
...
|
||||||
|
# #elif FAV_COLOR == "red"
|
||||||
|
...
|
||||||
|
# #else
|
||||||
|
...
|
||||||
|
# #endif
|
||||||
|
|
||||||
|
C (*.c, *.h), C++ (*.cpp, *.cxx, *.cc, *.h, *.hpp, *.hxx, *.hh),
|
||||||
|
Java (*.java), PHP (*.php) or C# (*.cs) files:
|
||||||
|
|
||||||
|
// #define FAV_COLOR 'blue'
|
||||||
|
...
|
||||||
|
/* #ifndef FAV_COLOR */
|
||||||
|
...
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
Fortran 77 (*.f) or 90/95 (*.f90) files:
|
||||||
|
|
||||||
|
C #if COEFF == 'var'
|
||||||
|
...
|
||||||
|
C #endif
|
||||||
|
|
||||||
|
And other languages.
|
||||||
|
|
||||||
|
Variables embraced by @ will be substitute by its value in the emitted
|
||||||
|
lines. For example if we define NAME="Yuan Xulei", the input file:
|
||||||
|
<p>Hello I'm @NAME@!</p>
|
||||||
|
will output:
|
||||||
|
<p>Hello I'm Yuan Xulei!</p>
|
||||||
|
|
||||||
|
Preprocessor Syntax
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Valid statements:
|
||||||
|
#define <var> [<value>]
|
||||||
|
#undef <var>
|
||||||
|
#ifdef <var>
|
||||||
|
#ifndef <var>
|
||||||
|
#if <expr>
|
||||||
|
#elif <expr>
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
#error <error string>
|
||||||
|
#include "<file>"
|
||||||
|
#include <var>
|
||||||
|
@varName@
|
||||||
|
where <expr> is any valid Python expression.
|
||||||
|
- The expression after #if/elif may be a Python statement. It is an
|
||||||
|
error to refer to a variable that has not been defined by a -D
|
||||||
|
option or by an in-content #define.
|
||||||
|
- Special built-in methods for expressions:
|
||||||
|
defined(varName) Return true if given variable is defined.
|
||||||
|
|
||||||
|
|
||||||
|
Tips
|
||||||
|
----
|
||||||
|
|
||||||
|
A suggested file naming convention is to let input files to
|
||||||
|
preprocess be of the form <basename>.p.<ext> and direct the output
|
||||||
|
of preprocess to <basename>.<ext>, e.g.:
|
||||||
|
preprocess -o foo.py foo.p.py
|
||||||
|
The advantage is that other tools (esp. editors) will still
|
||||||
|
recognize the unpreprocessed file as the original language.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version_info__ = (1, 1, 0)
|
||||||
|
__version__ = '.'.join(map(str, __version_info__))
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import getopt
|
||||||
|
import types
|
||||||
|
import re
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---- exceptions
|
||||||
|
|
||||||
|
class PreprocessError(Exception):
|
||||||
|
def __init__(self, errmsg, file=None, lineno=None, line=None):
|
||||||
|
self.errmsg = str(errmsg)
|
||||||
|
self.file = file
|
||||||
|
self.lineno = lineno
|
||||||
|
self.line = line
|
||||||
|
Exception.__init__(self, errmsg, file, lineno, line)
|
||||||
|
def __str__(self):
|
||||||
|
s = ""
|
||||||
|
if self.file is not None:
|
||||||
|
s += self.file + ":"
|
||||||
|
if self.lineno is not None:
|
||||||
|
s += str(self.lineno) + ":"
|
||||||
|
if self.file is not None or self.lineno is not None:
|
||||||
|
s += " "
|
||||||
|
s += self.errmsg
|
||||||
|
#if self.line is not None:
|
||||||
|
# s += ": " + self.line
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---- global data
|
||||||
|
|
||||||
|
# Comment delimiter info.
|
||||||
|
# A mapping of content type to a list of 2-tuples defining the line
|
||||||
|
# prefix and suffix for a comment. Each prefix or suffix can either
|
||||||
|
# be a string (in which case it is transformed into a pattern allowing
|
||||||
|
# whitespace on either side) or a compiled regex.
|
||||||
|
_commentGroups = {
|
||||||
|
"Python": [ ('#', '') ],
|
||||||
|
"Perl": [ ('#', '') ],
|
||||||
|
"PHP": [ ('/*', '*/'), ('//', ''), ('#', '') ],
|
||||||
|
"Ruby": [ ('#', '') ],
|
||||||
|
"Tcl": [ ('#', '') ],
|
||||||
|
"Shell": [ ('#', '') ],
|
||||||
|
# Allowing for CSS and JavaScript comments in XML/HTML.
|
||||||
|
"XML": [ ('<!--', '-->'), ('/*', '*/'), ('//', '') ],
|
||||||
|
"HTML": [ ('<!--', '-->'), ('/*', '*/'), ('//', '') ],
|
||||||
|
"Makefile": [ ('#', '') ],
|
||||||
|
"JavaScript": [ ('/*', '*/'), ('//', '') ],
|
||||||
|
"CSS": [ ('/*', '*/') ],
|
||||||
|
"C": [ ('/*', '*/') ],
|
||||||
|
"C++": [ ('/*', '*/'), ('//', '') ],
|
||||||
|
"Java": [ ('/*', '*/'), ('//', '') ],
|
||||||
|
"C#": [ ('/*', '*/'), ('//', '') ],
|
||||||
|
"IDL": [ ('/*', '*/'), ('//', '') ],
|
||||||
|
"Text": [ ('#', '') ],
|
||||||
|
"Fortran": [ (re.compile(r'^[a-zA-Z*$]\s*'), ''), ('!', '') ],
|
||||||
|
"TeX": [ ('%', '') ],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---- internal logging facility
|
||||||
|
|
||||||
|
class _Logger:
|
||||||
|
DEBUG, INFO, WARN, ERROR, CRITICAL = range(5)
|
||||||
|
def __init__(self, name, level=None, streamOrFileName=sys.stderr):
|
||||||
|
self._name = name
|
||||||
|
if level is None:
|
||||||
|
self.level = self.WARN
|
||||||
|
else:
|
||||||
|
self.level = level
|
||||||
|
if type(streamOrFileName) == types.StringType:
|
||||||
|
self.stream = open(streamOrFileName, 'w')
|
||||||
|
self._opennedStream = 1
|
||||||
|
else:
|
||||||
|
self.stream = streamOrFileName
|
||||||
|
self._opennedStream = 0
|
||||||
|
def __del__(self):
|
||||||
|
if self._opennedStream:
|
||||||
|
self.stream.close()
|
||||||
|
def getLevel(self):
|
||||||
|
return self.level
|
||||||
|
def setLevel(self, level):
|
||||||
|
self.level = level
|
||||||
|
def _getLevelName(self, level):
|
||||||
|
levelNameMap = {
|
||||||
|
self.DEBUG: "DEBUG",
|
||||||
|
self.INFO: "INFO",
|
||||||
|
self.WARN: "WARN",
|
||||||
|
self.ERROR: "ERROR",
|
||||||
|
self.CRITICAL: "CRITICAL",
|
||||||
|
}
|
||||||
|
return levelNameMap[level]
|
||||||
|
def isEnabled(self, level):
|
||||||
|
return level >= self.level
|
||||||
|
def isDebugEnabled(self): return self.isEnabled(self.DEBUG)
|
||||||
|
def isInfoEnabled(self): return self.isEnabled(self.INFO)
|
||||||
|
def isWarnEnabled(self): return self.isEnabled(self.WARN)
|
||||||
|
def isErrorEnabled(self): return self.isEnabled(self.ERROR)
|
||||||
|
def isFatalEnabled(self): return self.isEnabled(self.FATAL)
|
||||||
|
def log(self, level, msg, *args):
|
||||||
|
if level < self.level:
|
||||||
|
return
|
||||||
|
message = "%s: %s: " % (self._name, self._getLevelName(level).lower())
|
||||||
|
message = message + (msg % args) + "\n"
|
||||||
|
self.stream.write(message)
|
||||||
|
self.stream.flush()
|
||||||
|
def debug(self, msg, *args):
|
||||||
|
self.log(self.DEBUG, msg, *args)
|
||||||
|
def info(self, msg, *args):
|
||||||
|
self.log(self.INFO, msg, *args)
|
||||||
|
def warn(self, msg, *args):
|
||||||
|
self.log(self.WARN, msg, *args)
|
||||||
|
def error(self, msg, *args):
|
||||||
|
self.log(self.ERROR, msg, *args)
|
||||||
|
def fatal(self, msg, *args):
|
||||||
|
self.log(self.CRITICAL, msg, *args)
|
||||||
|
|
||||||
|
log = _Logger("preprocess", _Logger.WARN)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---- internal support stuff
|
||||||
|
|
||||||
|
def _evaluate(expr, defines):
|
||||||
|
"""Evaluate the given expression string with the given context.
|
||||||
|
|
||||||
|
WARNING: This runs eval() on a user string. This is unsafe.
|
||||||
|
"""
|
||||||
|
#interpolated = _interpolate(s, defines)
|
||||||
|
try:
|
||||||
|
rv = eval(expr, {'defined':lambda v: v in defines}, defines)
|
||||||
|
except Exception, ex:
|
||||||
|
msg = str(ex)
|
||||||
|
if msg.startswith("name '") and msg.endswith("' is not defined"):
|
||||||
|
# A common error (at least this is presumed:) is to have
|
||||||
|
# defined(FOO) instead of defined('FOO')
|
||||||
|
# We should give a little as to what might be wrong.
|
||||||
|
# msg == "name 'FOO' is not defined" --> varName == "FOO"
|
||||||
|
varName = msg[len("name '"):-len("' is not defined")]
|
||||||
|
if expr.find("defined(%s)" % varName) != -1:
|
||||||
|
# "defined(FOO)" in expr instead of "defined('FOO')"
|
||||||
|
msg += " (perhaps you want \"defined('%s')\" instead of "\
|
||||||
|
"\"defined(%s)\")" % (varName, varName)
|
||||||
|
elif msg.startswith("invalid syntax"):
|
||||||
|
msg = "invalid syntax: '%s'" % expr
|
||||||
|
raise PreprocessError(msg, defines['__FILE__'], defines['__LINE__'])
|
||||||
|
log.debug("evaluate %r -> %s (defines=%r)", expr, rv, defines)
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
#---- module API
|
||||||
|
|
||||||
|
def preprocess(infile, outfile=sys.stdout, defines={},
|
||||||
|
force=0, keepLines=0, includePath=[], substitute=0,
|
||||||
|
contentType=None, contentTypesRegistry=None,
|
||||||
|
__preprocessedFiles=None):
|
||||||
|
"""Preprocess the given file.
|
||||||
|
|
||||||
|
"infile" is the input path.
|
||||||
|
"outfile" is the output path or stream (default is sys.stdout).
|
||||||
|
"defines" is a dictionary of defined variables that will be
|
||||||
|
understood in preprocessor statements. Keys must be strings and,
|
||||||
|
currently, only the truth value of any key's value matters.
|
||||||
|
"force" will overwrite the given outfile if it already exists. Otherwise
|
||||||
|
an IOError will be raise if the outfile already exists.
|
||||||
|
"keepLines" will cause blank lines to be emitted for preprocessor lines
|
||||||
|
and content lines that would otherwise be skipped.
|
||||||
|
"includePath" is a list of directories to search for given #include
|
||||||
|
directives. The directory of the file being processed is presumed.
|
||||||
|
"substitute", if true, will allow substitution of defines into emitted
|
||||||
|
lines. (NOTE: This substitution will happen within program strings
|
||||||
|
as well. This may not be what you expect.)
|
||||||
|
"contentType" can be used to specify the content type of the input
|
||||||
|
file. It not given, it will be guessed.
|
||||||
|
"contentTypesRegistry" is an instance of ContentTypesRegistry. If not specified
|
||||||
|
a default registry will be created.
|
||||||
|
"__preprocessedFiles" (for internal use only) is used to ensure files
|
||||||
|
are not recusively preprocessed.
|
||||||
|
|
||||||
|
Returns the modified dictionary of defines or raises PreprocessError if
|
||||||
|
there was some problem.
|
||||||
|
"""
|
||||||
|
if __preprocessedFiles is None:
|
||||||
|
__preprocessedFiles = []
|
||||||
|
log.info("preprocess(infile=%r, outfile=%r, defines=%r, force=%r, "\
|
||||||
|
"keepLines=%r, includePath=%r, contentType=%r, "\
|
||||||
|
"__preprocessedFiles=%r)", infile, outfile, defines, force,
|
||||||
|
keepLines, includePath, contentType, __preprocessedFiles)
|
||||||
|
absInfile = os.path.normpath(os.path.abspath(infile))
|
||||||
|
if absInfile in __preprocessedFiles:
|
||||||
|
raise PreprocessError("detected recursive #include of '%s'"\
|
||||||
|
% infile)
|
||||||
|
__preprocessedFiles.append(os.path.abspath(infile))
|
||||||
|
|
||||||
|
# Determine the content type and comment info for the input file.
|
||||||
|
if contentType is None:
|
||||||
|
registry = contentTypesRegistry or getDefaultContentTypesRegistry()
|
||||||
|
contentType = registry.getContentType(infile)
|
||||||
|
if contentType is None:
|
||||||
|
contentType = "Text"
|
||||||
|
log.warn("defaulting content type for '%s' to '%s'",
|
||||||
|
infile, contentType)
|
||||||
|
try:
|
||||||
|
cgs = _commentGroups[contentType]
|
||||||
|
except KeyError:
|
||||||
|
raise PreprocessError("don't know comment delimiters for content "\
|
||||||
|
"type '%s' (file '%s')"\
|
||||||
|
% (contentType, infile))
|
||||||
|
|
||||||
|
# Generate statement parsing regexes. Basic format:
|
||||||
|
# <comment-prefix> <preprocessor-stmt> <comment-suffix>
|
||||||
|
# Examples:
|
||||||
|
# <!-- #if foo -->
|
||||||
|
# ...
|
||||||
|
# <!-- #endif -->
|
||||||
|
#
|
||||||
|
# # #if BAR
|
||||||
|
# ...
|
||||||
|
# # #else
|
||||||
|
# ...
|
||||||
|
# # #endif
|
||||||
|
stmts = ['#\s*(?P<op>if|elif|ifdef|ifndef)\s+(?P<expr>.*?)',
|
||||||
|
'#\s*(?P<op>else|endif)',
|
||||||
|
'#\s*(?P<op>error)\s+(?P<error>.*?)',
|
||||||
|
'#\s*(?P<op>define)\s+(?P<var>[^\s]*?)(\s+(?P<val>.+?))?',
|
||||||
|
'#\s*(?P<op>undef)\s+(?P<var>[^\s]*?)',
|
||||||
|
'#\s*(?P<op>include)\s+"(?P<fname>.*?)"',
|
||||||
|
r'#\s*(?P<op>include)\s+(?P<var>[^\s]+?)',
|
||||||
|
]
|
||||||
|
patterns = []
|
||||||
|
for stmt in stmts:
|
||||||
|
# The comment group prefix and suffix can either be just a
|
||||||
|
# string or a compiled regex.
|
||||||
|
for cprefix, csuffix in cgs:
|
||||||
|
if hasattr(cprefix, "pattern"):
|
||||||
|
pattern = cprefix.pattern
|
||||||
|
else:
|
||||||
|
pattern = r"^\s*%s\s*" % re.escape(cprefix)
|
||||||
|
pattern += stmt
|
||||||
|
if hasattr(csuffix, "pattern"):
|
||||||
|
pattern += csuffix.pattern
|
||||||
|
else:
|
||||||
|
pattern += r"\s*%s\s*$" % re.escape(csuffix)
|
||||||
|
patterns.append(pattern)
|
||||||
|
stmtRes = [re.compile(p) for p in patterns]
|
||||||
|
|
||||||
|
# Process the input file.
|
||||||
|
# (Would be helpful if I knew anything about lexing and parsing
|
||||||
|
# simple grammars.)
|
||||||
|
fin = open(infile, 'r')
|
||||||
|
lines = fin.readlines()
|
||||||
|
fin.close()
|
||||||
|
if type(outfile) in types.StringTypes:
|
||||||
|
if force and os.path.exists(outfile):
|
||||||
|
os.chmod(outfile, 0777)
|
||||||
|
os.remove(outfile)
|
||||||
|
fout = open(outfile, 'w')
|
||||||
|
else:
|
||||||
|
fout = outfile
|
||||||
|
|
||||||
|
defines['__FILE__'] = infile
|
||||||
|
SKIP, EMIT = range(2) # states
|
||||||
|
states = [(EMIT, # a state is (<emit-or-skip-lines-in-this-section>,
|
||||||
|
0, # <have-emitted-in-this-if-block>,
|
||||||
|
0)] # <have-seen-'else'-in-this-if-block>)
|
||||||
|
lineNum = 0
|
||||||
|
for line in lines:
|
||||||
|
lineNum += 1
|
||||||
|
log.debug("line %d: %r", lineNum, line)
|
||||||
|
defines['__LINE__'] = lineNum
|
||||||
|
|
||||||
|
# Is this line a preprocessor stmt line?
|
||||||
|
#XXX Could probably speed this up by optimizing common case of
|
||||||
|
# line NOT being a preprocessor stmt line.
|
||||||
|
for stmtRe in stmtRes:
|
||||||
|
match = stmtRe.match(line)
|
||||||
|
if match:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
match = None
|
||||||
|
|
||||||
|
if match:
|
||||||
|
op = match.group("op")
|
||||||
|
log.debug("%r stmt (states: %r)", op, states)
|
||||||
|
if op == "define":
|
||||||
|
if not (states and states[-1][0] == SKIP):
|
||||||
|
var, val = match.group("var", "val")
|
||||||
|
if val is None:
|
||||||
|
val = None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
val = eval(val, {}, {})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
defines[var] = val
|
||||||
|
elif op == "undef":
|
||||||
|
if not (states and states[-1][0] == SKIP):
|
||||||
|
var = match.group("var")
|
||||||
|
try:
|
||||||
|
del defines[var]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
elif op == "include":
|
||||||
|
if not (states and states[-1][0] == SKIP):
|
||||||
|
if "var" in match.groupdict():
|
||||||
|
# This is the second include form: #include VAR
|
||||||
|
var = match.group("var")
|
||||||
|
f = defines[var]
|
||||||
|
else:
|
||||||
|
# This is the first include form: #include "path"
|
||||||
|
f = match.group("fname")
|
||||||
|
|
||||||
|
for d in [os.path.dirname(infile)] + includePath:
|
||||||
|
fname = os.path.normpath(os.path.join(d, f))
|
||||||
|
if os.path.exists(fname):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise PreprocessError("could not find #include'd file "\
|
||||||
|
"\"%s\" on include path: %r"\
|
||||||
|
% (f, includePath))
|
||||||
|
defines = preprocess(fname, fout, defines, force,
|
||||||
|
keepLines, includePath, substitute,
|
||||||
|
contentTypesRegistry=contentTypesRegistry,
|
||||||
|
__preprocessedFiles=__preprocessedFiles)
|
||||||
|
elif op in ("if", "ifdef", "ifndef"):
|
||||||
|
if op == "if":
|
||||||
|
expr = match.group("expr")
|
||||||
|
elif op == "ifdef":
|
||||||
|
expr = "defined('%s')" % match.group("expr")
|
||||||
|
elif op == "ifndef":
|
||||||
|
expr = "not defined('%s')" % match.group("expr")
|
||||||
|
try:
|
||||||
|
if states and states[-1][0] == SKIP:
|
||||||
|
# Were are nested in a SKIP-portion of an if-block.
|
||||||
|
states.append((SKIP, 0, 0))
|
||||||
|
elif _evaluate(expr, defines):
|
||||||
|
states.append((EMIT, 1, 0))
|
||||||
|
else:
|
||||||
|
states.append((SKIP, 0, 0))
|
||||||
|
except KeyError:
|
||||||
|
raise PreprocessError("use of undefined variable in "\
|
||||||
|
"#%s stmt" % op, defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif op == "elif":
|
||||||
|
expr = match.group("expr")
|
||||||
|
try:
|
||||||
|
if states[-1][2]: # already had #else in this if-block
|
||||||
|
raise PreprocessError("illegal #elif after #else in "\
|
||||||
|
"same #if block", defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif states[-1][1]: # if have emitted in this if-block
|
||||||
|
states[-1] = (SKIP, 1, 0)
|
||||||
|
elif states[:-1] and states[-2][0] == SKIP:
|
||||||
|
# Were are nested in a SKIP-portion of an if-block.
|
||||||
|
states[-1] = (SKIP, 0, 0)
|
||||||
|
elif _evaluate(expr, defines):
|
||||||
|
states[-1] = (EMIT, 1, 0)
|
||||||
|
else:
|
||||||
|
states[-1] = (SKIP, 0, 0)
|
||||||
|
except IndexError:
|
||||||
|
raise PreprocessError("#elif stmt without leading #if "\
|
||||||
|
"stmt", defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif op == "else":
|
||||||
|
try:
|
||||||
|
if states[-1][2]: # already had #else in this if-block
|
||||||
|
raise PreprocessError("illegal #else after #else in "\
|
||||||
|
"same #if block", defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif states[-1][1]: # if have emitted in this if-block
|
||||||
|
states[-1] = (SKIP, 1, 1)
|
||||||
|
elif states[:-1] and states[-2][0] == SKIP:
|
||||||
|
# Were are nested in a SKIP-portion of an if-block.
|
||||||
|
states[-1] = (SKIP, 0, 1)
|
||||||
|
else:
|
||||||
|
states[-1] = (EMIT, 1, 1)
|
||||||
|
except IndexError:
|
||||||
|
raise PreprocessError("#else stmt without leading #if "\
|
||||||
|
"stmt", defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif op == "endif":
|
||||||
|
try:
|
||||||
|
states.pop()
|
||||||
|
except IndexError:
|
||||||
|
raise PreprocessError("#endif stmt without leading #if"\
|
||||||
|
"stmt", defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
elif op == "error":
|
||||||
|
if not (states and states[-1][0] == SKIP):
|
||||||
|
error = match.group("error")
|
||||||
|
raise PreprocessError("#error: "+error, defines['__FILE__'],
|
||||||
|
defines['__LINE__'], line)
|
||||||
|
log.debug("states: %r", states)
|
||||||
|
if keepLines:
|
||||||
|
fout.write("\n")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if states[-1][0] == EMIT:
|
||||||
|
log.debug("emit line (%s)" % states[-1][1])
|
||||||
|
# Substitute all defines into line.
|
||||||
|
# XXX Should avoid recursive substitutions. But that
|
||||||
|
# would be a pain right now.
|
||||||
|
sline = line
|
||||||
|
if substitute:
|
||||||
|
for name in reversed(sorted(defines, key=len)):
|
||||||
|
value = defines[name]
|
||||||
|
sline = sline.replace("@" + name + "@", str(value))
|
||||||
|
fout.write(sline)
|
||||||
|
elif keepLines:
|
||||||
|
log.debug("keep blank line (%s)" % states[-1][1])
|
||||||
|
fout.write("\n")
|
||||||
|
else:
|
||||||
|
log.debug("skip line (%s)" % states[-1][1])
|
||||||
|
except IndexError:
|
||||||
|
raise PreprocessError("superfluous #endif before this line",
|
||||||
|
defines['__FILE__'],
|
||||||
|
defines['__LINE__'])
|
||||||
|
if len(states) > 1:
|
||||||
|
raise PreprocessError("unterminated #if block", defines['__FILE__'],
|
||||||
|
defines['__LINE__'])
|
||||||
|
elif len(states) < 1:
|
||||||
|
raise PreprocessError("superfluous #endif on or before this line",
|
||||||
|
defines['__FILE__'], defines['__LINE__'])
|
||||||
|
|
||||||
|
if fout != outfile:
|
||||||
|
fout.close()
|
||||||
|
|
||||||
|
return defines
|
||||||
|
|
||||||
|
|
||||||
|
#---- content-type handling
|
||||||
|
|
||||||
|
_gDefaultContentTypes = """
|
||||||
|
# Default file types understood by "preprocess.py".
|
||||||
|
#
|
||||||
|
# Format is an extension of 'mime.types' file syntax.
|
||||||
|
# - '#' indicates a comment to the end of the line.
|
||||||
|
# - a line is:
|
||||||
|
# <filetype> [<pattern>...]
|
||||||
|
# where,
|
||||||
|
# <filetype>'s are equivalent in spirit to the names used in the Windows
|
||||||
|
# registry in HKCR, but some of those names suck or are inconsistent;
|
||||||
|
# and
|
||||||
|
# <pattern> is a suffix (pattern starts with a '.'), a regular expression
|
||||||
|
# (pattern is enclosed in '/' characters), a full filename (anything
|
||||||
|
# else).
|
||||||
|
#
|
||||||
|
# Notes on case-sensitivity:
|
||||||
|
#
|
||||||
|
# A suffix pattern is case-insensitive on Windows and case-sensitive
|
||||||
|
# elsewhere. A filename pattern is case-sensitive everywhere. A regex
|
||||||
|
# pattern's case-sensitivity is defined by the regex. This means it is by
|
||||||
|
# default case-sensitive, but this can be changed using Python's inline
|
||||||
|
# regex option syntax. E.g.:
|
||||||
|
# Makefile /^(?i)makefile.*$/ # case-INsensitive regex
|
||||||
|
|
||||||
|
Python .py
|
||||||
|
Python .pyw
|
||||||
|
Perl .pl
|
||||||
|
Ruby .rb
|
||||||
|
Tcl .tcl
|
||||||
|
XML .xml
|
||||||
|
XML .kpf
|
||||||
|
XML .xul
|
||||||
|
XML .rdf
|
||||||
|
XML .xslt
|
||||||
|
XML .xsl
|
||||||
|
XML .wxs
|
||||||
|
XML .wxi
|
||||||
|
HTML .htm
|
||||||
|
HTML .html
|
||||||
|
XML .xhtml
|
||||||
|
Makefile /^[Mm]akefile.*$/
|
||||||
|
PHP .php
|
||||||
|
JavaScript .js
|
||||||
|
JavaScript .ts
|
||||||
|
CSS .css
|
||||||
|
C++ .c # C++ because then we can use //-style comments
|
||||||
|
C++ .cpp
|
||||||
|
C++ .cxx
|
||||||
|
C++ .cc
|
||||||
|
C++ .h
|
||||||
|
C++ .hpp
|
||||||
|
C++ .hxx
|
||||||
|
C++ .hh
|
||||||
|
IDL .idl
|
||||||
|
Text .txt
|
||||||
|
Fortran .f
|
||||||
|
Fortran .f90
|
||||||
|
Shell .sh
|
||||||
|
Shell .csh
|
||||||
|
Shell .ksh
|
||||||
|
Shell .zsh
|
||||||
|
Java .java
|
||||||
|
C# .cs
|
||||||
|
TeX .tex
|
||||||
|
|
||||||
|
# Some Komodo-specific file extensions
|
||||||
|
Python .ksf # Fonts & Colors scheme files
|
||||||
|
Text .kkf # Keybinding schemes files
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ContentTypesRegistry:
|
||||||
|
"""A class that handles determining the filetype of a given path.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
>>> registry = ContentTypesRegistry()
|
||||||
|
>>> registry.getContentType("foo.py")
|
||||||
|
"Python"
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, contentTypesPaths=None):
|
||||||
|
self.contentTypesPaths = contentTypesPaths
|
||||||
|
self._load()
|
||||||
|
|
||||||
|
def _load(self):
|
||||||
|
from os.path import dirname, join, exists
|
||||||
|
|
||||||
|
self.suffixMap = {}
|
||||||
|
self.regexMap = {}
|
||||||
|
self.filenameMap = {}
|
||||||
|
|
||||||
|
self._loadContentType(_gDefaultContentTypes)
|
||||||
|
localContentTypesPath = join(dirname(__file__), "content.types")
|
||||||
|
if exists(localContentTypesPath):
|
||||||
|
log.debug("load content types file: `%r'" % localContentTypesPath)
|
||||||
|
self._loadContentType(open(localContentTypesPath, 'r').read())
|
||||||
|
for path in (self.contentTypesPaths or []):
|
||||||
|
log.debug("load content types file: `%r'" % path)
|
||||||
|
self._loadContentType(open(path, 'r').read())
|
||||||
|
|
||||||
|
def _loadContentType(self, content, path=None):
|
||||||
|
"""Return the registry for the given content.types file.
|
||||||
|
|
||||||
|
The registry is three mappings:
|
||||||
|
<suffix> -> <content type>
|
||||||
|
<regex> -> <content type>
|
||||||
|
<filename> -> <content type>
|
||||||
|
"""
|
||||||
|
for line in content.splitlines(0):
|
||||||
|
words = line.strip().split()
|
||||||
|
for i in range(len(words)):
|
||||||
|
if words[i][0] == '#':
|
||||||
|
del words[i:]
|
||||||
|
break
|
||||||
|
if not words: continue
|
||||||
|
contentType, patterns = words[0], words[1:]
|
||||||
|
if not patterns:
|
||||||
|
if line[-1] == '\n': line = line[:-1]
|
||||||
|
raise PreprocessError("bogus content.types line, there must "\
|
||||||
|
"be one or more patterns: '%s'" % line)
|
||||||
|
for pattern in patterns:
|
||||||
|
if pattern.startswith('.'):
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
# Suffix patterns are case-insensitive on Windows.
|
||||||
|
pattern = pattern.lower()
|
||||||
|
self.suffixMap[pattern] = contentType
|
||||||
|
elif pattern.startswith('/') and pattern.endswith('/'):
|
||||||
|
self.regexMap[re.compile(pattern[1:-1])] = contentType
|
||||||
|
else:
|
||||||
|
self.filenameMap[pattern] = contentType
|
||||||
|
|
||||||
|
def getContentType(self, path):
|
||||||
|
"""Return a content type for the given path.
|
||||||
|
|
||||||
|
@param path {str} The path of file for which to guess the
|
||||||
|
content type.
|
||||||
|
@returns {str|None} Returns None if could not determine the
|
||||||
|
content type.
|
||||||
|
"""
|
||||||
|
basename = os.path.basename(path).rstrip(".in")
|
||||||
|
contentType = None
|
||||||
|
# Try to determine from the path.
|
||||||
|
if not contentType and self.filenameMap.has_key(basename):
|
||||||
|
contentType = self.filenameMap[basename]
|
||||||
|
log.debug("Content type of '%s' is '%s' (determined from full "\
|
||||||
|
"path).", path, contentType)
|
||||||
|
# Try to determine from the suffix.
|
||||||
|
if not contentType and '.' in basename:
|
||||||
|
suffix = "." + basename.split(".")[-1]
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
# Suffix patterns are case-insensitive on Windows.
|
||||||
|
suffix = suffix.lower()
|
||||||
|
if self.suffixMap.has_key(suffix):
|
||||||
|
contentType = self.suffixMap[suffix]
|
||||||
|
log.debug("Content type of '%s' is '%s' (determined from "\
|
||||||
|
"suffix '%s').", path, contentType, suffix)
|
||||||
|
# Try to determine from the registered set of regex patterns.
|
||||||
|
if not contentType:
|
||||||
|
for regex, ctype in self.regexMap.items():
|
||||||
|
if regex.search(basename):
|
||||||
|
contentType = ctype
|
||||||
|
log.debug("Content type of '%s' is '%s' (matches regex '%s')",
|
||||||
|
path, contentType, regex.pattern)
|
||||||
|
break
|
||||||
|
# Try to determine from the file contents.
|
||||||
|
content = open(path, 'rb').read()
|
||||||
|
if content.startswith("<?xml"): # cheap XML sniffing
|
||||||
|
contentType = "XML"
|
||||||
|
return contentType
|
||||||
|
|
||||||
|
_gDefaultContentTypesRegistry = None
|
||||||
|
def getDefaultContentTypesRegistry():
|
||||||
|
global _gDefaultContentTypesRegistry
|
||||||
|
if _gDefaultContentTypesRegistry is None:
|
||||||
|
_gDefaultContentTypesRegistry = ContentTypesRegistry()
|
||||||
|
return _gDefaultContentTypesRegistry
|
||||||
|
|
||||||
|
|
||||||
|
#---- internal support stuff
|
||||||
|
#TODO: move other internal stuff down to this section
|
||||||
|
|
||||||
|
try:
|
||||||
|
reversed
|
||||||
|
except NameError:
|
||||||
|
# 'reversed' added in Python 2.4 (http://www.python.org/doc/2.4/whatsnew/node7.html)
|
||||||
|
def reversed(seq):
|
||||||
|
rseq = list(seq)
|
||||||
|
rseq.reverse()
|
||||||
|
for item in rseq:
|
||||||
|
yield item
|
||||||
|
try:
|
||||||
|
sorted
|
||||||
|
except NameError:
|
||||||
|
# 'sorted' added in Python 2.4. Note that I'm only implementing enough
|
||||||
|
# of sorted as is used in this module.
|
||||||
|
def sorted(seq, key=None):
|
||||||
|
identity = lambda x: x
|
||||||
|
key_func = (key or identity)
|
||||||
|
sseq = list(seq)
|
||||||
|
sseq.sort(lambda self, other: cmp(key_func(self), key_func(other)))
|
||||||
|
for item in sseq:
|
||||||
|
yield item
|
||||||
|
|
||||||
|
|
||||||
|
#---- mainline
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
try:
|
||||||
|
optlist, args = getopt.getopt(argv[1:], 'hVvo:D:fkI:sc:',
|
||||||
|
['help', 'version', 'verbose', 'force', 'keep-lines',
|
||||||
|
'substitute', 'content-types-path='])
|
||||||
|
except getopt.GetoptError, msg:
|
||||||
|
sys.stderr.write("preprocess: error: %s. Your invocation was: %s\n"\
|
||||||
|
% (msg, argv))
|
||||||
|
sys.stderr.write("See 'preprocess --help'.\n")
|
||||||
|
return 1
|
||||||
|
outfile = sys.stdout
|
||||||
|
defines = {}
|
||||||
|
force = 0
|
||||||
|
keepLines = 0
|
||||||
|
substitute = 0
|
||||||
|
includePath = []
|
||||||
|
contentTypesPaths = []
|
||||||
|
for opt, optarg in optlist:
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
sys.stdout.write(__doc__)
|
||||||
|
return 0
|
||||||
|
elif opt in ('-V', '--version'):
|
||||||
|
sys.stdout.write("preprocess %s\n" % __version__)
|
||||||
|
return 0
|
||||||
|
elif opt in ('-v', '--verbose'):
|
||||||
|
log.setLevel(log.DEBUG)
|
||||||
|
elif opt == '-o':
|
||||||
|
outfile = optarg
|
||||||
|
if opt in ('-f', '--force'):
|
||||||
|
force = 1
|
||||||
|
elif opt == '-D':
|
||||||
|
if optarg.find('=') != -1:
|
||||||
|
var, val = optarg.split('=', 1)
|
||||||
|
try:
|
||||||
|
val = int(val)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
var, val = optarg, None
|
||||||
|
defines[var] = val
|
||||||
|
elif opt in ('-k', '--keep-lines'):
|
||||||
|
keepLines = 1
|
||||||
|
elif opt == '-I':
|
||||||
|
includePath.append(optarg)
|
||||||
|
elif opt in ('-s', '--substitute'):
|
||||||
|
substitute = 1
|
||||||
|
elif opt in ('-c', '--content-types-path'):
|
||||||
|
contentTypesPaths.append(optarg)
|
||||||
|
|
||||||
|
if len(args) != 1:
|
||||||
|
sys.stderr.write("preprocess: error: incorrect number of "\
|
||||||
|
"arguments: argv=%r\n" % argv)
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
infile = args[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
contentTypesRegistry = ContentTypesRegistry(contentTypesPaths)
|
||||||
|
preprocess(infile, outfile, defines, force, keepLines, includePath,
|
||||||
|
substitute, contentTypesRegistry=contentTypesRegistry)
|
||||||
|
except PreprocessError, ex:
|
||||||
|
if log.isDebugEnabled():
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
else:
|
||||||
|
sys.stderr.write("preprocess: error: %s\n" % str(ex))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
__file__ = sys.argv[0]
|
||||||
|
sys.exit( main(sys.argv) )
|
||||||
|
|
|
@ -20,9 +20,6 @@ var inBrowser = typeof console !== "undefined" && console.info;
|
||||||
declare var putstr;
|
declare var putstr;
|
||||||
declare var printErr;
|
declare var printErr;
|
||||||
|
|
||||||
/** @const */ var release: boolean = true;
|
|
||||||
/** @const */ var profile: boolean = true;
|
|
||||||
|
|
||||||
declare var dateNow: () => number;
|
declare var dateNow: () => number;
|
||||||
|
|
||||||
declare var dump: (message: string) => void;
|
declare var dump: (message: string) => void;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче