Merge branch 'master' into cmake

This commit is contained in:
Sam Edwards 2015-11-07 20:06:59 -08:00
commit c902774cfd
646 changed files with 26557 additions and 20976 deletions

View File

@ -81,14 +81,18 @@ sudo apt-get install build-essential pkg-config python-dev libpng-dev libjpeg-de
```
Once Panda3D has built, you can either install the .deb or .rpm package that
it produced (if relevant to your platform, and you added --installer). On
other systems, you will need to use the installpanda script to install it onto
your system. Careful: it is not easy to uninstall Panda3D in this way!
it produced, depending on which Linux distribution you are using. For example,
to install the package on Debian or Ubuntu, use this:
```bash
python2.7 makepanda/installpanda.py --prefix=/usr/local
sudo dpkg -i panda3d*.deb
```
If you are not using a Linux distribution that supports .deb or .rpm packages, you
may have to use the installpanda.py script instead, which will directly copy the
files into the appropriate locations on your computer. You may have to run the
`ldconfig` tool in order to update your library cache after installing Panda3D.
Mac OS X
--------
@ -110,3 +114,20 @@ by the release number, eg. 10.6 or 10.7.
If the build was successful, makepanda will have generated a .dmg file in
the source directory containing the installer. Simply open it and run the
package file in order to install the SDK onto your system.
Reporting Issues
================
If you encounter any bugs when using Panda3D, please report them in the bug
tracker. This is hosted at:
https://bugs.launchpad.net/panda3d
Make sure to first use the search function to see if the bug has already been
reported. When filling out a bug report, make sure that you include as much
information as possible to help the developers track down the issue, such as
your version of Panda3D, operating system, architecture, and any code and
models that are necessary for the developers to reproduce the issue.
If you're not sure whether you've encountered a bug, feel free to ask about
it in the forums or the IRC channel first.

View File

@ -1 +0,0 @@
#include "ai_composite1.cxx"

View File

@ -23,6 +23,8 @@ class Actor(DirectObject, NodePath):
LoaderOptions.LFConvertAnim)
validateSubparts = ConfigVariableBool('validate-subparts', True)
mergeLODBundles = ConfigVariableBool('merge-lod-bundles', True)
allowAsyncBind = ConfigVariableBool('allow-async-bind', True)
class PartDef:
@ -170,10 +172,10 @@ class Actor(DirectObject, NodePath):
# ['common']; when it is false, __animControlDict has one key
# per each LOD name.
if mergeLODBundles == None:
if mergeLODBundles is None:
# If this isn't specified, it comes from the Config.prc
# file.
self.mergeLODBundles = base.config.GetBool('merge-lod-bundles', True)
self.mergeLODBundles = Actor.mergeLODBundles.getValue()
else:
self.mergeLODBundles = mergeLODBundles
@ -181,8 +183,8 @@ class Actor(DirectObject, NodePath):
# asynchronous animation binding. This requires that you have
# run "egg-optchar -preload" on your animation and models to
# generate the appropriate AnimPreloadTable.
if allowAsyncBind == None:
self.allowAsyncBind = base.config.GetBool('allow-async-bind', True)
if allowAsyncBind is None:
self.allowAsyncBind = Actor.allowAsyncBind.getValue()
else:
self.allowAsyncBind = allowAsyncBind

View File

@ -179,9 +179,9 @@ class GravityWalker(DirectObject.DirectObject):
# a higher or lower value depending on whether you want an avatar
# that is outside of the world to step up to the floor when they
# get under valid floor:
cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
self.cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
cRayNode = CollisionNode('GW.cRayNode')
cRayNode.addSolid(cRay)
cRayNode.addSolid(self.cRay)
self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
cRayNode.setFromCollideMask(bitmask)
cRayNode.setIntoCollideMask(BitMask32.allOff())
@ -697,8 +697,4 @@ class GravityWalker(DirectObject.DirectObject):
# There are sometimes issues if the collision ray height is
# so tall that it collides with multiple levels of floors.
def setCollisionRayHeight(self, height):
oldNode = self.avatarNodePath.getNode(0)
cRayNode = oldNode.getChild(2)
cRayNode.removeSolid(0)
cRay = CollisionRay(0.0, 0.0, height, 0.0, 0.0, -1.0)
cRayNode.addSolid(cRay)
self.cRay.setOrigin(0.0, 0.0, height)

View File

@ -20,8 +20,10 @@
#ifdef HAVE_PYTHON
#undef HAVE_LONG_LONG // NSPR and Python both define this.
#define PY_SSIZE_T_CLEAN 1
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
// Python 2.5 adds Py_ssize_t; earlier versions don't have it.

View File

@ -36,7 +36,7 @@ int main(int argc, char *mb_argv[]) {
size_t len = mbstowcs(NULL, mb_argv[i], 0);
argv[i] = new wchar_t[len + 1];
mbstowcs(argv[i], mb_argv[i], len);
argv[i][len] = NULL;
argv[i][len] = 0;
}
// Just for good measure
argv[argc] = NULL;

View File

@ -235,7 +235,7 @@ class Notifier:
Prints the string to output followed by a newline.
"""
if self.streamWriter:
self.streamWriter.appendData(string + '\n')
self.streamWriter.write(string + '\n')
else:
print >> sys.stderr, string

View File

@ -1,44 +0,0 @@
##############################################################################
#
# cleancvstree
#
# Cleancvstree searches a CVS tree for files that are not in CVS, and
# deletes them. Be careful using it --- it's very aggressive.
#
##############################################################################
import sys,os
def cleanCvsTree(dir):
try:
sub = os.listdir(dir)
except:
print "Could not read directory: "+dir
return
valid = {}
try:
readentries = 0
cvsent = open(dir + "/CVS/Entries")
for line in cvsent:
words = line.split("/")
if (len(words) > 1):
valid[words[1]] = 1
cvsent.close()
readentries = 1
except:
print "Could not read "+dir+"/CVS/Entries"
if (readentries):
for file in sub:
if (os.path.isfile(dir+"/"+file)):
if (valid.has_key(file)==0):
os.unlink(dir+"/"+file)
for file in sub:
if (file != "CVS"):
if (os.path.isdir(dir+"/"+file)):
cleanCvsTree(dir+"/"+file)
if (os.path.isdir(sys.argv[1])==0):
print "Not a directory: "+sys.argv[1]
os.exit(1)
cleanCvsTree(sys.argv[1])

View File

@ -1,124 +0,0 @@
#!/usr/bin/env python
"""This script generates the panda3d-date.tar.gz tarball for a file
release of panda3d onto the SourceForge download site.
Options:
-d cvsroot
Specifies the CVSROOT string to use to tag and export the
tree. The default is $SFROOT if it is defined, or $CVSROOT
otherwise.
-r tag
Specifies the tag to export from. If this parameter is
specified, the tree is not tagged again; otherwise, the
current head of the CVS tree is tagged with the file version
name.
-m module
Specifies the module to check out and build. The default is
panda3d.
"""
import sys
import os
import os.path
import getopt
import time
import glob
import shutil
CVSROOT = os.getenv('SFROOT') or os.getenv('CVSROOT')
ORIGTAG = ''
MODULE = 'panda3d'
def usage(code, msg = ''):
print >> sys.stderr, __doc__
print >> sys.stderr, msg
sys.exit(code)
try:
opts, args = getopt.getopt(sys.argv[1:], 'd:r:m:h')
except getopt.error, msg:
usage(1, msg)
for opt, arg in opts:
if opt == '-d':
CVSROOT = arg
elif opt == '-r':
ORIGTAG = arg
elif opt == '-m':
MODULE = arg
elif opt == '-h':
usage(0)
if not CVSROOT:
usage(1, 'CVSROOT must have a value.')
if not MODULE:
usage(1, 'MODULE must have a value.')
basename = MODULE + '-' + time.strftime("%Y-%m-%d")
tarfile = basename + '.tar.gz'
zipfile = basename + '.zip'
if os.path.exists(basename):
print basename, 'already exists in the local directory!'
sys.exit(1)
if not ORIGTAG:
# If we weren't given a starting tag, make one.
tag = basename
print 'Tagging sources.'
cmd = 'cvs -f -d "%s" rtag -F -r HEAD "%s" "%s"' % (CVSROOT, tag, MODULE)
if os.system(cmd) != 0:
sys.exit(1)
else:
# Otherwise, we were given a starting tag, so use it.
tag = ORIGTAG
print 'Checking out "%s" as "%s".' % (MODULE, basename)
cmd = 'cvs -z3 -f -d "%s" export -r "%s" -d "%s" "%s"' % (CVSROOT, tag,
basename, MODULE)
if os.system(cmd) != 0:
sys.exit(1)
# Move the contents of the doc module into the root directory where people
# will expect to see it.
docdir = basename + os.sep + 'doc'
if os.path.exists(docdir):
files = glob.glob(docdir + os.sep + '*')
for file in files:
shutil.copy(file, basename)
os.remove(file)
os.rmdir(docdir)
# Generate the autoconf scripts for ppremake.
if MODULE == 'ppremake':
ppremakedir = basename
else:
ppremakedir = basename + os.sep + 'ppremake'
if os.path.exists(ppremakedir):
cmd = 'cd "./%s" && aclocal && autoheader && automake --foreign -a && autoconf' % (ppremakedir)
if os.system(cmd) != 0:
sys.exit(1)
# Generate the tarball.
print 'Generating %s' % (tarfile)
if os.path.exists(tarfile):
os.remove(tarfile)
cmd = 'tar cf - "%s" | gzip -9 > "%s"' % (basename, tarfile)
if os.system(cmd) != 0:
sys.exit(1)
# Also generate a zip file.
print 'Generating %s' % (zipfile)
if os.path.exists(zipfile):
os.remove(zipfile)
cmd = 'zip -9rq "%s" "%s"' % (zipfile, basename)
if os.system(cmd) != 0:
sys.exit(1)
shutil.rmtree(basename)

View File

@ -1,6 +1,5 @@
from direct.distributed.DistributedSmoothNodeBase import DistributedSmoothNodeBase
from direct.distributed.GridParent import GridParent
from pandac.PandaModules import EmbeddedValue
class GridChild:
"""

View File

@ -1,97 +0,0 @@
"""
CInterval-extensions module: contains methods to extend functionality
of the CInterval class
"""
from direct.directnotify.DirectNotifyGlobal import directNotify
notify = directNotify.newCategory("Interval")
def setT(self, t):
# Overridden from the C++ function to call privPostEvent
# afterward. We do this by renaming the C++ function in
# FFIRename.
self._priv__cSetT(t)
self.privPostEvent()
def play(self, t0 = 0.0, duration = None, scale = 1.0):
self.notify.error("using deprecated CInterval.play() interface")
if duration: # None or 0 implies full length
self.start(t0, t0 + duration, scale)
else:
self.start(t0, -1, scale)
def stop(self):
self.notify.error("using deprecated CInterval.stop() interface")
self.finish()
def setFinalT(self):
self.notify.error("using deprecated CInterval.setFinalT() interface")
self.finish()
def privPostEvent(self):
# Call after calling any of the priv* methods to do any required
# Python finishing steps.
t = self.getT()
if hasattr(self, "setTHooks"):
for func in self.setTHooks:
func(t)
def popupControls(self, tl = None):
"""
Popup control panel for interval.
"""
from direct.showbase.TkGlobal import Toplevel, Frame, Button, LEFT, X, Pmw
import math
from direct.tkwidgets import EntryScale
if tl == None:
tl = Toplevel()
tl.title('Interval Controls')
outerFrame = Frame(tl)
def entryScaleCommand(t, s=self):
s.setT(t)
s.pause()
self.es = es = EntryScale.EntryScale(
outerFrame, text = self.getName(),
min = 0, max = math.floor(self.getDuration() * 100) / 100,
command = entryScaleCommand)
es.set(self.getT(), fCommand = 0)
es.pack(expand = 1, fill = X)
bf = Frame(outerFrame)
# Jump to start and end
def toStart(s=self, es=es):
s.clearToInitial()
s.setT(0)
es.set(0, fCommand = 0)
def toEnd(s=self):
s.setT(s.getDuration())
s.pause()
jumpToStart = Button(bf, text = '<<', command = toStart)
# Stop/play buttons
def doPlay(s=self, es=es):
s.resume(es.get())
stop = Button(bf, text = 'Stop',
command = lambda s=self: s.pause())
play = Button(
bf, text = 'Play',
command = doPlay)
jumpToEnd = Button(bf, text = '>>', command = toEnd)
jumpToStart.pack(side = LEFT, expand = 1, fill = X)
play.pack(side = LEFT, expand = 1, fill = X)
stop.pack(side = LEFT, expand = 1, fill = X)
jumpToEnd.pack(side = LEFT, expand = 1, fill = X)
bf.pack(expand = 1, fill = X)
outerFrame.pack(expand = 1, fill = X)
# Add function to update slider during setT calls
def update(t, es=es):
es.set(t, fCommand = 0)
if not hasattr(self, "setTHooks"):
self.setTHooks = []
self.setTHooks.append(update)
self.setWantsTCallback(1)
# Clear out function on destroy
def onDestroy(e, s=self, u=update):
if u in s.setTHooks:
s.setTHooks.remove(u)
tl.bind('<Destroy>', onDestroy)

View File

@ -1,50 +0,0 @@
def __str__(self):
return self.getStringValue()
def __hash__(self):
raise AttributeError, "ConfigVariables are not immutable."
def ls(self):
from pandac.Notify import Notify
self.write(Notify.out())
def __int__(self):
return int(self.getValue())
def __long__(self):
return long(self.getValue())
def __float__(self):
return float(self.getValue())
def __nonzero__(self):
return bool(self.getValue())
def __oct__(self):
return oct(self.getValue())
def __hex__(self):
return hex(self.getValue())
def __cmp__(self, other):
return self.getValue().__cmp__(other)
def __neg__(self):
return -self.getValue()
def __coerce__(self, other):
return (self.getValue(), other)
def __len__(self):
return self.getNumWords()
def __getitem__(self, n):
if n < 0 or n >= self.getNumWords():
raise IndexError
return self.getWord(n)
def __setitem__(self, n, value):
if n < 0 or n > self.getNumWords():
raise IndexError
self.setWord(n, value)

View File

@ -1,5 +0,0 @@
def __getitem__(self, n):
if n < 0 or n >= self.getNumWords():
raise IndexError
return self.getWord(n)

View File

@ -1,5 +0,0 @@
def __getitem__(self, n):
if n < 0 or n >= self.getNumWords():
raise IndexError
return self.getWord(n)

View File

@ -1,5 +0,0 @@
def __getitem__(self, n):
if n < 0 or n >= self.getNumWords():
raise IndexError
return self.getWord(n)

View File

@ -1,18 +0,0 @@
def __hash__(self):
raise AttributeError, "ConfigVariables are not immutable."
def ls(self):
from pandac.Notify import Notify
self.write(Notify.out())
def __cmp__(self, other):
return list(self).__cmp__(list(other))
def __len__(self):
return self.getNumValues()
def __getitem__(self, n):
if n < 0 or n >= self.getNumUniqueValues():
raise IndexError
return self.getUniqueValue(n)

View File

@ -1,6 +0,0 @@
def __len__(self):
return self.getValue().__len__()
def __getitem__(self, n):
return self.getValue().__getitem__(n)

View File

@ -1,31 +0,0 @@
"""
HTTPChannel-extensions module: contains methods to extend functionality
of the HTTPChannel class
"""
def spawnTask(self, name = None, callback = None, extraArgs = []):
"""Spawns a task to service the download recently requested
via beginGetDocument(), etc., and/or downloadToFile() or
downloadToRam(). If a callback is specified, that function is
called when the download is complete, passing in the extraArgs
given.
Returns the newly-spawned task.
"""
if not name:
name = str(self.getUrl())
from direct.task import Task
task = Task.Task(self.doTask)
task.callback = callback
task.callbackArgs = extraArgs
return taskMgr.add(task, name)
def doTask(self, task):
from direct.task import Task
if self.run():
return Task.cont
if task.callback:
task.callback(*task.callbackArgs)
return Task.done

View File

@ -1,16 +0,0 @@
"""
Mat3-extensions module: contains methods to extend functionality
of the LMatrix3f class.
"""
def __repr__(self):
return '%s(\n%s,\n%s,\n%s)' % (
self.__class__.__name__, self.getRow(0).pPrintValues(), self.getRow(1).pPrintValues(), self.getRow(2).pPrintValues())
def pPrintValues(self):
"""
Pretty print
"""
return "\n%s\n%s\n%s" % (
self.getRow(0).pPrintValues(), self.getRow(1).pPrintValues(), self.getRow(2).pPrintValues())

View File

@ -1,27 +0,0 @@
"""
MouseWatcherRegion-extensions module: contains methods to extend
functionality of the MouseWatcherRegion class
"""
def setRelative(self, np, left, right, bottom, top):
"""setRelation(NodePath np, float left, float right,
float bottom, float top)
Sets the region to represnt the indicated rectangle, relative
to the given NodePath. It is assumed that np represents some
node parented within the render2d hierarchy.
"""
from pandac import Point3
# Get the relative transform to the node.
mat = np.getMat(render2d)
# Use this matrix to transform the corners of the region.
ll = mat.xformPoint(Point3.Point3(left, 0, bottom))
ur = mat.xformPoint(Point3.Point3(right, 0, top))
# Set the frame to the transformed coordinates.
self.setFrame(ll[0], ur[0], ll[2], ur[2])

View File

@ -1,20 +0,0 @@
"""
Node-extensions module: contains methods to extend functionality
of the Node class
"""
def isHidden(self):
"""Determine if a node is hidden. Just pick the first parent,
since this is an ambiguous question for instanced nodes"""
import RenderRelation
import PruneTransition
rrClass = RenderRelation.RenderRelation.getClassType()
if self.getNumParents(rrClass) > 0:
arc = self.getParent(rrClass, 0)
if arc.hasTransition(PruneTransition.PruneTransition.getClassType()):
return 1
else:
return arc.getParent().isHidden()
else:
return 0

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +0,0 @@
"""
NurbsCurveEvaluator-extensions module: contains methods to extend
functionality of the NurbsCurveEvaluator class
"""
def getKnots(self):
"""Returns the knot vector as a Python list of floats"""
knots = []
for i in range(self.getNumKnots()):
knots.append(self.getKnot(i))
return knots
def getVertices(self, relTo = None):
"""Returns the vertices as a Python list of Vec4's, relative
to the indicated space if given."""
verts = []
if relTo:
for i in range(self.getNumVertices()):
verts.append(self.getVertex(i, relTo))
else:
for i in range(self.getNumVertices()):
verts.append(self.getVertex(i))
return verts

View File

@ -1,36 +0,0 @@
"""
NurbsSurfaceEvaluator-extensions module: contains methods to extend
functionality of the NurbsSurfaceEvaluator class
"""
def getUKnots(self):
"""Returns the U knot vector as a Python list of floats"""
knots = []
for i in range(self.getNumUKnots()):
knots.append(self.getUKnot(i))
return knots
def getVKnots(self):
"""Returns the V knot vector as a Python list of floats"""
knots = []
for i in range(self.getNumVKnots()):
knots.append(self.getVKnot(i))
return knots
def getVertices(self, relTo = None):
"""Returns the vertices as a 2-d Python list of Vec4's, relative
to the indicated space if given."""
verts = []
for ui in range(self.getNumUVertices()):
v = []
if relTo:
for vi in range(self.getNumVVertices()):
v.append(self.getVertex(ui, vi, relTo))
else:
for vi in range(self.getNumVVertices()):
v.append(self.getVertex(ui, vi))
verts.append(v)
return verts

View File

@ -1,6 +0,0 @@
def getSystems(self):
l = []
for i in range(self.getNumSystems()):
l.append(self.getSystem(l))
return l

View File

@ -1,3 +0,0 @@
// For now, since we are not installing Python files, this file can
// remain empty.

View File

@ -1,83 +0,0 @@
"""
Contains methods to extend functionality
of the SpriteParticleRenderer class
"""
# Initialize class variables for texture, source file and node for texture and
# node path textures to None. These will be initialized to a hardcoded default
# or whatever the user specifies in his/her Configrc variable the first time they
# are accessed
# Will use instance copy of this in functions below
sourceTextureName = None
sourceFileName = None
sourceNodeName = None
def getSourceTextureName(self):
if self.sourceTextureName == None:
SpriteParticleRenderer.sourceTextureName = base.config.GetString(
'particle-sprite-texture', 'phase_3/maps/feyes.jpg')
# Return instance copy of class variable
return self.sourceTextureName
def setSourceTextureName(self, name):
# Set instance copy of class variable
self.sourceTextureName = name
def setTextureFromFile(self, fileName = None):
if fileName == None:
fileName = self.getSourceTextureName()
else:
self.setSourceTextureName(fileName)
t = loader.loadTexture(fileName)
if (t != None):
self.setTexture(t)
else:
print "Couldn't find rendererSpriteTexture file: %s" % fileName
def getSourceFileName(self):
if self.sourceFileName == None:
SpriteParticleRenderer.sourceFileName = base.config.GetString(
'particle-sprite-model', 'phase_3.5/models/props/suit-particles')
# Return instance copy of class variable
return self.sourceFileName
def setSourceFileName(self, name):
# Set instance copy of class variable
self.sourceFileName = name
def getSourceNodeName(self):
if self.sourceNodeName == None:
SpriteParticleRenderer.sourceNodeName = base.config.GetString(
'particle-sprite-node', '**/fire')
# Return instance copy of class variable
return self.sourceNodeName
def setSourceNodeName(self, name):
# Set instance copy of class variable
self.sourceNodeName = name
def setTextureFromNode(self, modelName = None, nodeName = None):
if modelName == None:
modelName = self.getSourceFileName()
else:
self.setSourceFileName(modelName)
if nodeName == None:
nodeName = self.getSourceNodeName()
else:
self.setSourceNodeName(nodeName)
# Load model and get texture
m = loader.loadModel(modelName)
if (m == None):
print "SpriteParticleRenderer: Couldn't find model: %s!" % modelName
return None
nodeName = self.getSourceNodeName()
np = m.find(nodeName)
if np.isEmpty():
print "SpriteParticleRenderer: Couldn't find node: %s!" % nodeName
m.removeNode()
return None
self.setFromNode(np)
m.removeNode()

View File

@ -1,15 +0,0 @@
"""
VBase3-extensions module: contains methods to extend functionality
of the VBase3 class
"""
def __repr__(self):
return '%s(%s, %s, %s)' % (
self.__class__.__name__, self[0], self[1], self[2])
def pPrintValues(self):
"""
Pretty print
"""
return "% 10.4f, % 10.4f, % 10.4f" % (self[0], self[1], self[2])

View File

@ -1,15 +0,0 @@
"""
VBase4-extensions module: contains methods to extend functionality
of the VBase4 class
"""
def __repr__(self):
return '%s(%s, %s, %s, %s)' % (
self.__class__.__name__, self[0], self[1], self[2], self[3])
def pPrintValues(self):
"""
Pretty print
"""
return '% 10.4f, % 10.4f, % 10.4f, % 10.4f' % (self[0], self[1], self[2], self[3])

View File

@ -1 +0,0 @@
from PandaModules import *

View File

@ -13,22 +13,9 @@ __all__ = ["AppRunner", "dummyAppRunner", "ArgumentError"]
import sys
import os
import __builtin__
if 'VFSImporter' in sys.modules:
# If we've already got a VFSImporter module defined at the
# toplevel, we must have come in here by way of the
# p3dPythonRun.cxx program, which starts out by importing a frozen
# VFSImporter. Let's make sure we don't have two VFSImporter
# modules.
import VFSImporter
import direct.showbase
direct.showbase.VFSImporter = VFSImporter
sys.modules['direct.showbase.VFSImporter'] = VFSImporter
else:
# Otherwise, we can import the VFSImporter normally.
from direct.showbase import VFSImporter
import __builtin__ as builtins
from direct.showbase import VFSImporter
from direct.showbase.DirectObject import DirectObject
from panda3d.core import VirtualFileSystem, Filename, Multifile, loadPrcFileData, unloadPrcFile, getModelPath, WindowProperties, ExecutionEnvironment, PandaSystem, Notify, StreamWriter, ConfigVariableString, ConfigPageManager
from panda3d.direct import init_app_for_gui
@ -472,7 +459,7 @@ class AppRunner(DirectObject):
file.unlink()
return False
if not fileSpec.fullVerify(pathname = localPathname):
if not fileSpec.fullVerify(pathname = localPathname, notify = self.notify):
# No good after download.
self.notify.info("%s is still no good after downloading." % (url))
return False
@ -570,14 +557,14 @@ class AppRunner(DirectObject):
for packageData in hostData.packages:
totalSize += packageData.totalSize
self.notify.info("Total Panda3D disk space used: %s MB" % (
(totalSize + 524288) / 1048576))
(totalSize + 524288) // 1048576))
if self.verifyContents == self.P3DVCNever:
# We're not allowed to delete anything anyway.
return
self.notify.info("Configured max usage is: %s MB" % (
(self.maxDiskUsage + 524288) / 1048576))
(self.maxDiskUsage + 524288) // 1048576))
if totalSize <= self.maxDiskUsage:
# Still within budget; no need to clean up anything.
return
@ -635,13 +622,13 @@ class AppRunner(DirectObject):
try:
taskMgr.run()
except SystemExit:
except SystemExit as err:
# Presumably the window has already been shut down here, but shut
# it down again for good measure.
if hasattr(__builtin__, "base"):
if hasattr(builtins, "base"):
base.destroy()
self.notify.info("Normal exit.")
self.notify.info("Normal exit with status %s." % repr(err.code))
raise
except:
@ -697,9 +684,10 @@ class AppRunner(DirectObject):
# Replace the builtin open and file symbols so user code will get
# our versions by default, which can open and read files out of
# the multifile.
__builtin__.file = file.file
__builtin__.open = file.open
__builtin__.execfile = file.execfile
builtins.open = file.open
if sys.version_info < (3, 0):
builtins.file = file.open
builtins.execfile = file.execfile
os.listdir = file.listdir
os.walk = file.walk
os.path.join = file.join

View File

@ -5,7 +5,7 @@ to build for as many platforms as possible. """
__all__ = ["Standalone", "Installer"]
import os, sys, subprocess, tarfile, shutil, time, zipfile, socket, getpass, struct
from cStringIO import StringIO
from io import BytesIO, TextIOWrapper
from direct.directnotify.DirectNotifyGlobal import *
from direct.showbase.AppRunnerGlobal import appRunner
from panda3d.core import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile
@ -21,8 +21,8 @@ try:
except ImportError:
pwd = None
# Make sure this matches with the magic in p3dEmbed.cxx.
P3DEMBED_MAGIC = "\xFF\x3D\x3D\x00"
# Make sure this matches with the magic in p3dEmbedMain.cxx.
P3DEMBED_MAGIC = 0xFF3D3D00
# This filter function is used when creating
# an archive that should be owned by root.
@ -73,7 +73,7 @@ class Standalone:
self.tempDir = Filename.temporary("", self.basename, "") + "/"
self.tempDir.makeDir()
self.host = HostInfo(PandaSystem.getPackageHostUrl(), appRunner = appRunner, hostDir = self.tempDir, asMirror = False)
self.host = HostInfo(PandaSystem.getPackageHostUrl(), appRunner = appRunner, hostDir = self.tempDir, asMirror = False, perPlatform = True)
self.http = HTTPClient.getGlobalPtr()
if not self.host.hasContentsFile:
@ -99,6 +99,9 @@ class Standalone:
if len(platforms) == 0:
Standalone.notify.warning("No platforms found to build for!")
if 'win32' in platforms and 'win_i386' in platforms:
platforms.remove('win32')
outputDir = Filename(outputDir + "/")
outputDir.makeDir()
for platform in platforms:
@ -158,10 +161,10 @@ class Standalone:
# Find the magic size string and replace it with the real size,
# regardless of the endianness of the p3dembed executable.
hex_size = hex(size)[2:].rjust(8, "0")
enc_size = "".join([chr(int(hex_size[i] + hex_size[i + 1], 16)) for i in range(0, len(hex_size), 2)])
p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC, enc_size)
p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC[::-1], enc_size[::-1])
p3dembed_data = p3dembed_data.replace(struct.pack('>I', P3DEMBED_MAGIC),
struct.pack('>I', size))
p3dembed_data = p3dembed_data.replace(struct.pack('<I', P3DEMBED_MAGIC),
struct.pack('<I', size))
# Write the output file
Standalone.notify.info("Creating %s..." % output)
@ -170,12 +173,15 @@ class Standalone:
ohandle.write(p3dembed_data)
# Write out the tokens. Set log_basename to the basename by default
tokens = {"log_basename" : self.basename}
tokens = {"log_basename": self.basename}
tokens.update(self.tokens)
tokens.update(extraTokens)
for token in tokens.items():
ohandle.write("\0%s=%s" % token)
ohandle.write("\0\0")
for key, value in tokens.items():
ohandle.write(b"\0")
ohandle.write(key.encode('ascii'))
ohandle.write(b"=")
ohandle.write(value.encode())
ohandle.write(b"\0\0")
# Buffer the p3d file to the output file. 1 MB buffer size.
phandle = open(self.p3dfile.toOsSpecific(), "rb")
@ -233,7 +239,7 @@ class PackageTree:
if hostUrl in self.hosts:
return self.hosts[hostUrl]
host = HostInfo(hostUrl, appRunner = appRunner, hostDir = self.hostDir, asMirror = False)
host = HostInfo(hostUrl, appRunner = appRunner, hostDir = self.hostDir, asMirror = False, perPlatform = True)
if not host.hasContentsFile:
if not host.readContentsFile():
if not host.downloadContentsFile(self.http):
@ -391,7 +397,7 @@ class Icon:
vfs = VirtualFileSystem.getGlobalPtr()
stream = vfs.openWriteFile(fn, False, True)
icns = open(stream, 'wb')
icns.write('icns\0\0\0\0')
icns.write(b'icns\0\0\0\0')
icon_types = {16: 'is32', 32: 'il32', 48: 'ih32', 128: 'it32'}
mask_types = {16: 's8mk', 32: 'l8mk', 48: 'h8mk', 128: 't8mk'}
@ -404,7 +410,7 @@ class Icon:
if pngtype is None:
continue
icns.write(png_types[size])
icns.write('\0\0\0\0')
icns.write(b'\0\0\0\0')
start = icns.tell()
image.write(stream, "", pngtype)
@ -444,6 +450,7 @@ class Installer:
notify = directNotify.newCategory("Installer")
def __init__(self, p3dfile, shortname, fullname, version, tokens = {}):
self.p3dFilename = p3dfile
if not shortname:
shortname = p3dfile.getBasenameWoExtension()
self.shortname = shortname
@ -477,22 +484,16 @@ class Installer:
if not self.authoremail and ' ' not in uname:
self.authoremail = "%s@%s" % (uname, socket.gethostname())
self.standalone = Standalone(p3dfile, tokens)
self.tempDir = Filename.temporary("", self.shortname, "") + "/"
self.tempDir.makeDir()
self.__tempRoots = {}
# Load the p3d file to read out the required packages
mf = Multifile()
if not mf.openRead(p3dfile):
if not mf.openRead(self.p3dFilename):
Installer.notify.error("Not a Panda3D application: %s" % (p3dfile))
return
# Now load the p3dInfo file.
self.hostUrl = PandaSystem.getPackageHostUrl()
if not self.hostUrl:
self.hostUrl = self.standalone.host.hostUrl
self.hostUrl = None
self.requires = []
self.extracts = []
i = mf.findSubfile('p3d_info.xml')
if i >= 0:
stream = mf.openReadSubfile(i)
@ -511,14 +512,54 @@ class Installer:
p3dRequires.Attribute('host')))
p3dRequires = p3dRequires.NextSiblingElement('requires')
p3dExtract = p3dPackage.FirstChildElement('extract')
while p3dExtract:
filename = p3dExtract.Attribute('filename')
self.extracts.append(filename)
p3dExtract = p3dExtract.NextSiblingElement('extract')
if not self.fullname:
p3dConfig = p3dPackage.FirstChildElement('config')
if p3dConfig:
self.fullname = p3dConfig.Attribute('display_name')
else:
Installer.notify.warning("No p3d_info.xml was found in .p3d archive.")
mf.close()
if not self.hostUrl:
self.hostUrl = PandaSystem.getPackageHostUrl()
if not self.hostUrl:
self.hostUrl = self.standalone.host.hostUrl
Installer.notify.warning("No host URL was specified by .p3d archive. Falling back to %s" % (self.hostUrl))
if not self.fullname:
self.fullname = self.shortname
self.tempDir = Filename.temporary("", self.shortname, "") + "/"
self.tempDir.makeDir()
self.__tempRoots = {}
if self.extracts:
# Copy .p3d to a temporary file so we can remove the extracts.
p3dfile = Filename(self.tempDir, self.p3dFilename.getBasename())
shutil.copyfile(self.p3dFilename.toOsSpecific(), p3dfile.toOsSpecific())
mf = Multifile()
if not mf.openReadWrite(p3dfile):
Installer.notify.error("Failure to open %s for writing." % (p3dfile))
# We don't really need this silly thing when embedding, anyway.
mf.setHeaderPrefix("")
for fn in self.extracts:
if not mf.removeSubfile(fn):
Installer.notify.error("Failure to remove %s from multifile." % (p3dfile))
mf.repack()
mf.close()
self.standalone = Standalone(p3dfile, tokens)
def __del__(self):
try:
appRunner.rmtree(self.tempDir)
@ -533,6 +574,22 @@ class Installer:
if not self.includeRequires:
return
# Write out the extracts from the original .p3d.
if self.extracts:
mf = Multifile()
if not mf.openRead(self.p3dFilename):
Installer.notify.error("Failed to open .p3d archive: %s" % (filename))
for filename in self.extracts:
i = mf.findSubfile(filename)
if i < 0:
Installer.notify.error("Cannot find extract in .p3d archive: %s" % (filename))
continue
if not mf.extractSubfile(i, Filename(hostDir, filename)):
Installer.notify.error("Failed to extract file from .p3d archive: %s" % (filename))
mf.close()
pkgTree = PackageTree(platform, hostDir, self.hostUrl)
pkgTree.installPackage("images", None, self.standalone.host.hostUrl)
@ -618,6 +675,9 @@ class Installer:
if len(platforms) == 0:
Installer.notify.warning("No platforms found to build for!")
if 'win32' in platforms and 'win_i386' in platforms:
platforms.remove('win32')
outputDir = Filename(outputDir + "/")
outputDir.makeDir()
for platform in platforms:
@ -660,7 +720,8 @@ class Installer:
Filename(tempdir, "usr/bin/").makeDir()
if self.includeRequires:
extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower()}
extraTokens = {"host_dir" : "/usr/lib/" + self.shortname.lower(),
"start_dir" : "/usr/lib/" + self.shortname.lower()}
else:
extraTokens = {}
self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform, extraTokens)
@ -712,7 +773,7 @@ class Installer:
print >>desktop, "Type=Application"
desktop.close()
if self.includeRequires:
if self.includeRequires or self.extracts:
hostDir = Filename(tempdir, "usr/lib/%s/" % self.shortname.lower())
hostDir.makeDir()
self.installPackagesInto(hostDir, platform)
@ -742,16 +803,18 @@ class Installer:
tempdir, totsize = self.__buildTempLinux(platform)
# Create a control file in memory.
controlfile = StringIO()
print >>controlfile, "Package: %s" % self.shortname.lower()
print >>controlfile, "Version: %s" % self.version
print >>controlfile, "Maintainer: %s <%s>" % (self.authorname, self.authoremail)
print >>controlfile, "Section: games"
print >>controlfile, "Priority: optional"
print >>controlfile, "Architecture: %s" % arch
print >>controlfile, "Installed-Size: %d" % -(-totsize / 1024)
print >>controlfile, "Description: %s" % self.fullname
print >>controlfile, "Depends: libc6, libgcc1, libstdc++6, libx11-6"
controlfile = BytesIO()
cout = TextIOWrapper(controlfile, encoding='utf-8', newline='')
cout.write(u"Package: %s\n" % self.shortname.lower())
cout.write(u"Version: %s\n" % self.version)
cout.write(u"Maintainer: %s <%s>\n" % (self.authorname, self.authoremail))
cout.write(u"Section: games\n")
cout.write(u"Priority: optional\n")
cout.write(u"Architecture: %s\n" % arch)
cout.write(u"Installed-Size: %d\n" % -(-totsize // 1024))
cout.write(u"Description: %s\n" % self.fullname)
cout.write(u"Depends: libc6, libgcc1, libstdc++6, libx11-6\n")
cout.flush()
controlinfo = TarInfoRoot("control")
controlinfo.mtime = modtime
controlinfo.size = controlfile.tell()
@ -762,33 +825,43 @@ class Installer:
if output.exists():
output.unlink()
debfile = open(output.toOsSpecific(), "wb")
debfile.write("!<arch>\x0A")
debfile.write("debian-binary %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 4))
debfile.write("2.0\x0A")
debfile.write(b"!<arch>\x0A")
pad_mtime = str(modtime).encode().ljust(12, b' ')
# Write the control.tar.gz to the archive.
debfile.write("control.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0))
# The first entry is a special file that marks it a .deb.
debfile.write(b"debian-binary ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 4 \x60\x0A")
debfile.write(b"2.0\x0A")
# Write the control.tar.gz to the archive. We'll leave the
# size 0 for now, and go back and fill it in later.
debfile.write(b"control.tar.gz ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 0 \x60\x0A")
ctaroffs = debfile.tell()
ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot)
ctarfile.addfile(controlinfo, controlfile)
ctarfile.close()
ctarsize = debfile.tell() - ctaroffs
if (ctarsize & 1): debfile.write("\x0A")
if (ctarsize & 1): debfile.write(b"\x0A")
# Write the data.tar.gz to the archive.
debfile.write("data.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0))
# Write the data.tar.gz to the archive. Again, leave size 0.
debfile.write(b"data.tar.gz ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 0 \x60\x0A")
dtaroffs = debfile.tell()
dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot)
dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr")
dtarfile.close()
dtarsize = debfile.tell() - dtaroffs
if (dtarsize & 1): debfile.write("\x0A")
if (dtarsize & 1): debfile.write(b"\x0A")
# Write the correct sizes of the archives.
debfile.seek(ctaroffs - 12)
debfile.write("%-10ld" % ctarsize)
debfile.write(str(ctarsize).encode().ljust(10, b' '))
debfile.seek(dtaroffs - 12)
debfile.write("%-10ld" % dtarsize)
debfile.write(str(dtarsize).encode().ljust(10, b' '))
debfile.close()
@ -815,18 +888,20 @@ class Installer:
tempdir, totsize = self.__buildTempLinux(platform)
# Create a pkginfo file in memory.
pkginfo = StringIO()
print >>pkginfo, "# Generated using pdeploy"
print >>pkginfo, "# %s" % time.ctime(modtime)
print >>pkginfo, "pkgname = %s" % self.shortname.lower()
print >>pkginfo, "pkgver = %s" % pkgver
print >>pkginfo, "pkgdesc = %s" % self.fullname
print >>pkginfo, "builddate = %s" % modtime
print >>pkginfo, "packager = %s <%s>" % (self.authorname, self.authoremail)
print >>pkginfo, "size = %d" % totsize
print >>pkginfo, "arch = %s" % arch
pkginfo = BytesIO()
pout = TextIOWrapper(pkginfo, encoding='utf-8', newline='')
pout.write(u"# Generated using pdeploy\n")
pout.write(u"# %s\n" % time.ctime(modtime))
pout.write(u"pkgname = %s\n" % self.shortname.lower())
pout.write(u"pkgver = %s\n" % pkgver)
pout.write(u"pkgdesc = %s\n" % self.fullname)
pout.write(u"builddate = %s\n" % modtime)
pout.write(u"packager = %s <%s>\n" % (self.authorname, self.authoremail))
pout.write(u"size = %d\n" % totsize)
pout.write(u"arch = %s\n" % arch)
if self.licensename != "":
print >>pkginfo, "license = %s" % self.licensename
pout.write(u"license = %s\n" % self.licensename)
pout.flush()
pkginfoinfo = TarInfoRoot(".PKGINFO")
pkginfoinfo.mtime = modtime
pkginfoinfo.size = pkginfo.tell()
@ -853,7 +928,7 @@ class Installer:
exefile = Filename(output, "Contents/MacOS/" + self.shortname)
exefile.makeDir()
if self.includeRequires:
extraTokens = {"host_dir" : "../Resources"}
extraTokens = {"host_dir": "../Resources", "start_dir": "../Resources"}
else:
extraTokens = {}
self.standalone.build(exefile, platform, extraTokens)
@ -1064,7 +1139,7 @@ class Installer:
exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe")
exefile.unlink()
if self.includeRequires:
extraTokens = {"host_dir" : "."}
extraTokens = {"host_dir": ".", "start_dir": "."}
else:
extraTokens = {}
self.standalone.build(exefile, platform, extraTokens)

View File

@ -161,14 +161,14 @@ class HostInfo:
self.notify.info("Downloading contents file %s" % (request))
statusCode = None
statusString = ''
for attempt in range(ConfigVariableInt('contents-xml-dl-attempts', 3)):
for attempt in range(int(ConfigVariableInt('contents-xml-dl-attempts', 3))):
if attempt > 0:
self.notify.info("Retrying (%s)..."%(attempt,))
rf = Ramfile()
channel = http.makeChannel(False)
channel.getDocument(request)
if channel.downloadToRam(rf):
self.notify.warning("Successfully downloaded %s" % (url,))
self.notify.info("Successfully downloaded %s" % (url,))
break
else:
rf = None
@ -369,7 +369,7 @@ class HostInfo:
assert self.hostDir
self.__findHostXmlForHostDir(xcontents)
if not self.hostDir:
if self.rootDir and not self.hostDir:
self.hostDir = self.__determineHostDir(None, self.hostUrl)
# Get the list of packages available for download and/or import.
@ -403,7 +403,7 @@ class HostInfo:
self.hasContentsFile = True
# Now save the contents.xml file into the standard location.
if not self.appRunner or self.appRunner.verifyContents != self.appRunner.P3DVCNever:
if self.appRunner and self.appRunner.verifyContents != self.appRunner.P3DVCNever:
assert self.hostDir
filename = Filename(self.hostDir, 'contents.xml')
filename.makeDir()
@ -476,7 +476,7 @@ class HostInfo:
self.descriptiveName = descriptiveName
hostDirBasename = xhost.Attribute('host_dir')
if not self.hostDir:
if self.rootDir and not self.hostDir:
self.hostDir = self.__determineHostDir(hostDirBasename, self.hostUrl)
# Get the "download" URL, which is the source from which we
@ -513,17 +513,15 @@ class HostInfo:
PackageInfo, returns it. """
if not platform:
# Ensure that we're on the same page with non-specified
# platforms. We always use None, not empty string.
platform = None
platforms = self.packages.setdefault((name, version), {})
package = platforms.get(platform, None)
platforms = self.packages.setdefault((name, version or ""), {})
package = platforms.get("", None)
if not package:
package = PackageInfo(self, name, version, platform = platform,
solo = solo, asMirror = self.asMirror,
perPlatform = perPlatform)
platforms[platform] = package
platforms[platform or ""] = package
return package
@ -533,12 +531,12 @@ class HostInfo:
platform, if one is provided by this host, or None if not. """
assert self.hasContentsFile
platforms = self.packages.get((name, version or None), {})
platforms = self.packages.get((name, version or ""), {})
if platform is not None:
if platform:
# In this case, we are looking for a specific platform
# only.
return platforms.get(platform or None, None)
return platforms.get(platform, None)
# We are looking for one matching the current runtime
# platform. First, look for a package matching the current
@ -547,7 +545,7 @@ class HostInfo:
# If not found, look for one matching no particular platform.
if not package:
package = platforms.get(None, None)
package = platforms.get("", None)
return package
@ -563,7 +561,7 @@ class HostInfo:
if name and pn != name:
continue
if platform is None:
if not platform:
for p2 in platforms:
package = self.getPackage(pn, version, platform = p2)
if package:
@ -581,14 +579,12 @@ class HostInfo:
result = []
items = self.packages.items()
items.sort()
items = sorted(self.packages.items())
for key, platforms in items:
if self.perPlatform or includeAllPlatforms:
# If we maintain a different answer per platform,
# return all of them.
pitems = platforms.items()
pitems.sort()
pitems = sorted(platforms.items())
for pkey, package in pitems:
result.append(package)
else:
@ -597,7 +593,7 @@ class HostInfo:
# current platform, or no particular platform.
package = platforms.get(PandaSystem.getPlatform(), None)
if not package:
package = platforms.get(None, None)
package = platforms.get("", None)
if package:
result.append(package)
@ -701,7 +697,7 @@ class HostInfo:
# If we successfully got a hostname, we don't really need the
# full hash. We'll keep half of it.
keepHash = keepHash / 2;
keepHash = keepHash // 2
md = HashVal()
md.hashString(hostUrl)

View File

@ -277,7 +277,7 @@ class PackageInfo:
# We've already got one.
yield self.stepComplete; return
if self.host.appRunner and self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever:
if not self.host.appRunner or self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever:
# We're allowed to download it.
self.http = http
@ -523,7 +523,8 @@ class PackageInfo:
# In case of unexpected failures on the internet, we will retry
# the full download instead of just giving up.
for retry in range(core.ConfigVariableInt('package-full-dl-retries', 1)):
retries = core.ConfigVariableInt('package-full-dl-retries', 1).getValue()
for retry in range(retries):
self.installPlans.append(planB[:])
pc.stop()
@ -1151,7 +1152,7 @@ class PackageInfo:
thisDir = ScanDirectoryNode(self.getPackageDir(), ignoreUsageXml = True)
diskSpace = thisDir.getTotalSize()
self.notify.info("Package %s uses %s MB" % (
self.packageName, (diskSpace + 524288) / 1048576))
self.packageName, (diskSpace + 524288) // 1048576))
return diskSpace
def markUsed(self):

View File

@ -16,6 +16,7 @@ import types
import getpass
import struct
import subprocess
import copy
from direct.p3d.FileSpec import FileSpec
from direct.p3d.SeqValue import SeqValue
from direct.showbase import Loader
@ -185,7 +186,7 @@ class Packager:
def getKey(self):
""" Returns a tuple used for sorting the PackageEntry
objects uniquely per package. """
return (self.packageName, self.platform, self.version)
return (self.packageName, self.platform or "", self.version or "")
def fromFile(self, packageName, platform, version, solo, perPlatform,
installDir, descFilename, importDescFilename):
@ -299,8 +300,7 @@ class Packager:
xhost.InsertEndChild(xmirror)
if packager:
altHosts = self.altHosts.items()
altHosts.sort()
altHosts = sorted(self.altHosts.items())
for keyword, alt in altHosts:
he = packager.hosts.get(alt, None)
if he:
@ -372,9 +372,15 @@ class Packager:
self.requiredFilenames = []
self.requiredModules = []
# A list of required packages that were missing.
self.missingPackages = []
# This records the current list of modules we have added so
# far.
self.freezer = FreezeTool.Freezer(platform = self.packager.platform)
# Map of extensions to files to number (ignored by dir)
self.ignoredDirFiles = {}
def close(self):
""" Writes out the contents of the current package. Returns True
@ -385,6 +391,12 @@ class Packager:
message = 'Cannot generate packages without an installDir; use -i'
raise PackagerError, message
if self.ignoredDirFiles:
exts = sorted(self.ignoredDirFiles.keys())
total = sum([x for x in self.ignoredDirFiles.values()])
self.notify.warning("excluded %s files not marked for inclusion: %s" \
% (total, ", ".join(["'" + ext + "'" for ext in exts])))
if not self.host:
self.host = self.packager.host
@ -454,7 +466,7 @@ class Packager:
if self.p3dApplication:
allowPythonDev = self.configs.get('allow_python_dev', 0)
if int(allowPythonDev):
print "\n*** Generating %s.p3d with allow_python_dev enabled ***\n" % (self.packageName)
print("\n*** Generating %s.p3d with allow_python_dev enabled ***\n" % (self.packageName))
return result
@ -485,6 +497,12 @@ class Packager:
as a true package. Either is implemented with a
Multifile. """
if self.missingPackages:
missing = ', '.join([name for name, version in self.missingPackages])
self.notify.warning("Cannot build package %s due to missing dependencies: %s" % (self.packageName, missing))
self.cleanup()
return False
self.multifile = Multifile()
# Write the multifile to a temporary filename until we
@ -570,8 +588,7 @@ class Packager:
# Add known module names.
self.moduleNames = {}
modules = self.freezer.modules.items()
modules.sort()
modules = sorted(self.freezer.modules.items())
for newName, mdef in modules:
if mdef.guess:
# Not really a module.
@ -702,7 +719,7 @@ class Packager:
self.packageDesc = packageDir + self.packageDesc
self.packageImportDesc = packageDir + self.packageImportDesc
print "Generating %s" % (self.packageFilename)
print("Generating %s" % (self.packageFilename))
if self.p3dApplication:
self.packageFullpath = Filename(self.packager.p3dInstallDir, self.packageFilename)
@ -820,6 +837,14 @@ class Packager:
self.packager.contents[pe.getKey()] = pe
self.packager.contentsChanged = True
# Hack for coreapi package, to preserve backward compatibility
# with old versions of the runtime, which still called the
# 32-bit Windows platform "win32".
if self.packageName == "coreapi" and self.platform == "win_i386":
pe2 = copy.copy(pe)
pe2.platform = "win32"
self.packager.contents[pe2.getKey()] = pe2
self.cleanup()
return True
@ -1232,13 +1257,13 @@ class Packager:
elf.close()
return None
if not ident.startswith("\177ELF"):
if not ident.startswith(b"\177ELF"):
# No elf magic! Beware of orcs.
return None
# Make sure we read in the correct endianness and integer size
byteOrder = "<>"[ord(ident[5]) - 1]
elfClass = ord(ident[4]) - 1 # 0 = 32-bits, 1 = 64-bits
byteOrder = "<>"[ord(ident[5:6]) - 1]
elfClass = ord(ident[4:5]) - 1 # 0 = 32-bits, 1 = 64-bits
headerStruct = byteOrder + ("HHIIIIIHHHHHH", "HHIQQQIHHHHHH")[elfClass]
sectionStruct = byteOrder + ("4xI8xIII8xI", "4xI16xQQI12xQ")[elfClass]
dynamicStruct = byteOrder + ("iI", "qQ")[elfClass]
@ -1272,17 +1297,17 @@ class Packager:
elf.seek(offset)
data = elf.read(entsize)
tag, val = struct.unpack_from(dynamicStruct, data)
newSectionData = ""
newSectionData = b""
startReplace = None
pad = 0
# Read tags until we find a NULL tag.
while tag != 0:
if tag == 1: # A NEEDED entry. Read it from the string table.
filenames.append(stringTables[link][val : stringTables[link].find('\0', val)])
filenames.append(stringTables[link][val : stringTables[link].find(b'\0', val)])
elif tag == 15 or tag == 29:
rpath += stringTables[link][val : stringTables[link].find('\0', val)].split(':')
rpath += stringTables[link][val : stringTables[link].find(b'\0', val)].split(b':')
# An RPATH or RUNPATH entry.
if not startReplace:
startReplace = elf.tell() - entsize
@ -1296,7 +1321,7 @@ class Packager:
tag, val = struct.unpack_from(dynamicStruct, data)
if startReplace is not None:
newSectionData += data + ("\0" * pad)
newSectionData += data + (b"\0" * pad)
rewriteSections.append((startReplace, newSectionData))
elf.close()
@ -1329,7 +1354,7 @@ class Packager:
for offset, data in rewriteSections:
elf.seek(offset)
elf.write(data)
elf.write("\0" * pad)
elf.write(b"\0" * pad)
elf.close()
return filenames
@ -1468,6 +1493,10 @@ class Packager:
xhost = he.makeXml(packager = self.packager)
xpackage.InsertEndChild(xhost)
self.extracts.sort()
for name, xextract in self.extracts:
xpackage.InsertEndChild(xextract)
doc.InsertEndChild(xpackage)
# Write the xml file to a temporary file on disk, so we
@ -1813,7 +1842,10 @@ class Packager:
self.notify.warning(message)
return
self.freezer.addModule(moduleName, filename = file.filename)
if file.text:
self.freezer.addModule(moduleName, filename = file.filename, text = file.text)
else:
self.freezer.addModule(moduleName, filename = file.filename)
def addEggFile(self, file):
# Precompile egg files to bam's.
@ -2161,8 +2193,10 @@ class Packager:
ext = Filename(lowerName).getExtension()
if ext not in self.packager.nonuniqueExtensions:
self.skipFilenames[lowerName] = True
for moduleName, mdef in package.moduleNames.items():
self.skipModules[moduleName] = mdef
if not mdef.exclude:
self.skipModules[moduleName] = mdef
# Packager constructor
def __init__(self, platform = None):
@ -2185,6 +2219,9 @@ class Packager:
# ignoring any request to specify a particular download host,
# e.g. for testing and development.
self.ignoreSetHost = False
# Set this to true to verbosely log files ignored by dir().
self.verbosePrint = False
# This will be appended to the basename of any .p3d package,
# before the .p3d extension.
@ -2333,7 +2370,7 @@ class Packager:
# Binary files that are copied (and compressed) without
# processing.
self.binaryExtensions = [ 'ttf', 'TTF', 'mid', 'ico' ]
self.binaryExtensions = [ 'ttf', 'TTF', 'mid', 'ico', 'cur' ]
# Files that can have an existence in multiple different
# packages simultaneously without conflict.
@ -2373,7 +2410,7 @@ class Packager:
}
# Files that should be extracted to disk.
self.extractExtensions = self.executableExtensions[:] + self.manifestExtensions[:] + [ 'ico' ]
self.extractExtensions = self.executableExtensions[:] + self.manifestExtensions[:] + [ 'ico', 'cur' ]
# Files that indicate a platform dependency.
self.platformSpecificExtensions = self.executableExtensions[:]
@ -2390,6 +2427,14 @@ class Packager:
# should be added exactly byte-for-byte as they are.
self.unprocessedExtensions = []
# Files for which warnings should be suppressed when they are
# not handled by dir()
self.suppressWarningForExtensions = ['', 'pyc', 'pyo',
'p3d', 'pdef',
'c', 'C', 'cxx', 'cpp', 'h', 'H',
'hpp', 'pp', 'I', 'pem', 'p12', 'crt',
'o', 'obj', 'a', 'lib', 'bc', 'll']
# System files that should never be packaged. For
# case-insensitive filesystems (like Windows and OSX), put the
# lowercase filename here. Case-sensitive filesystems should
@ -2456,7 +2501,7 @@ class Packager:
if not os.path.isfile('/sbin/ldconfig'):
return False
handle = subprocess.Popen(['/sbin/ldconfig', '-p'], stdout=subprocess.PIPE)
handle = subprocess.Popen(['/sbin/ldconfig', '-p'], stdout=subprocess.PIPE, universal_newlines=True)
out, err = handle.communicate()
if handle.returncode != 0:
@ -2617,12 +2662,20 @@ class Packager:
if dirname.makeTrueCase():
searchPath.appendDirectory(dirname)
def _ensureExtensions(self):
self.knownExtensions = \
self.imageExtensions + \
self.modelExtensions + \
self.textExtensions + \
self.binaryExtensions + \
self.uncompressibleExtensions + \
self.unprocessedExtensions
def setup(self):
""" Call this method to initialize the class after filling in
some of the values in the constructor. """
self.knownExtensions = self.imageExtensions + self.modelExtensions + self.textExtensions + self.binaryExtensions + self.uncompressibleExtensions + self.unprocessedExtensions
self._ensureExtensions()
self.currentPackage = None
@ -2710,11 +2763,15 @@ class Packager:
# errors, and that the pdef file doesn't contain any really
# crazy Python code, all this will do is fill in the
# '__statements' list in the module scope.
fn = packageDef.toOsSpecific()
f = open(fn)
code = compile(f.read(), fn, 'exec')
f.close()
# It appears that having a separate globals and locals
# dictionary causes problems with resolving symbols within a
# class scope. So, we just use one dictionary, the globals.
execfile(packageDef.toOsSpecific(), globals)
exec(code, globals)
packages = []
@ -2979,10 +3036,10 @@ class Packager:
# environment.
return None
# Make sure we have a fresh version of the contents file.
host = appRunner.getHost(hostUrl)
if not host.readContentsFile():
if not host.downloadContentsFile(appRunner.http):
return None
if not host.downloadContentsFile(appRunner.http):
return None
packageInfos = []
packageInfo = host.getPackage(packageName, version, platform = platform)
@ -3031,7 +3088,7 @@ class Packager:
tuples = []
for package in packages:
version = self.__makeVersionTuple(package.version)
tuples.append((version, file))
tuples.append((version, package))
tuples.sort(reverse = True)
return [t[1] for t in tuples]
@ -3044,7 +3101,7 @@ class Packager:
tuples = []
for package in packages:
version = self.__makeVersionTuple(package.packageVersion)
tuples.append((version, file))
tuples.append((version, package))
tuples.sort(reverse = True)
return [t[1] for t in tuples]
@ -3103,9 +3160,9 @@ class Packager:
if panda1.version == panda2.version:
return True
print 'Rejecting package %s, version "%s": depends on %s, version "%s" instead of version "%s"' % (
print('Rejecting package %s, version "%s": depends on %s, version "%s" instead of version "%s"' % (
package.packageName, package.version,
panda1.packageName, panda1.version, panda2.version)
panda1.packageName, panda1.version, panda2.version))
return False
def __findPackageInRequires(self, packageName, list):
@ -3188,7 +3245,9 @@ class Packager:
requires = self.currentPackage.requires)
if not package:
message = 'Unknown package %s, version "%s"' % (packageName, version)
raise PackagerError, message
self.notify.warning(message)
self.currentPackage.missingPackages.append((packageName, pversion))
continue
self.requirePackage(package)
@ -3293,42 +3352,27 @@ class Packager:
producing their own custom panda3d for download. Should be
called before any other Python modules are named. """
# First, freeze just VFSImporter.py into its own
# _vfsimporter.pyd file. This one is a special case, because
# we need this code in order to load python files from the
# Multifile, so this file can't itself be in the Multifile.
# This module and all its dependencies come frozen into p3dpython.
# We should mark them as having already been added so that we don't
# add them again to the Multifile.
self.do_module('direct.showbase.VFSImporter')
self.currentPackage.freezer.done(addStartupModules=True)
self.currentPackage.freezer.writeCode(None)
self.currentPackage.addExtensionModules()
self.currentPackage.freezer.reset()
# This requires a bit of care, because we only want to freeze
# VFSImporter.py, and not any other part of direct. We do
# also want panda3d/__init__.py, though, since it would
# otherwise be part of the multifile.
self.do_excludeModule('direct')
# Import the actual VFSImporter module to get its filename on
# disk.
from direct.showbase import VFSImporter
filename = Filename.fromOsSpecific(VFSImporter.__file__)
self.do_module('VFSImporter', filename = filename)
self.do_freeze('_vfsimporter', compileToExe = False)
self.do_file('panda3d/core.pyd');
# Now that we're done freezing, explicitly add 'direct' to
# counteract the previous explicit excludeModule().
self.do_module('direct')
self.do_file('panda3d/_core.pyd', newDir='panda3d')
# This is the key Python module that is imported at runtime to
# start an application running.
self.do_module('direct.p3d.AppRunner')
# This is the main program that drives the runtime Python. It
# is responsible for loading _vfsimporter.pyd, and then
# importing direct.p3d.AppRunner, to start an application
# running. The program comes in two parts: an executable, and
# an associated dynamic library. Note that the .exe and .dll
# extensions are automatically replaced with the appropriate
# platform-specific extensions.
# is responsible for importing direct.p3d.AppRunner to start an
# application running. The program comes in two parts: an
# executable, and an associated dynamic library. Note that the
# .exe and .dll extensions are automatically replaced with the
# appropriate platform-specific extensions.
if self.platform.startswith('osx'):
# On Mac, we package up a P3DPython.app bundle. This
@ -3411,7 +3455,7 @@ class Packager:
freezer.addModule(moduleName, newName = newName)
else:
freezer.modules[newName] = freezer.modules[moduleName]
freezer.done(compileToExe = compileToExe)
freezer.done(addStartupModules = compileToExe)
dirname = ''
basename = filename
@ -3604,6 +3648,43 @@ class Packager:
filename = Filename(filename)
self.currentPackage.excludeFile(filename)
def do_includeExtensions(self, executableExtensions = None, extractExtensions = None,
imageExtensions = None, textExtensions = None,
uncompressibleExtensions = None, unprocessedExtensions = None,
suppressWarningForExtensions = None):
""" Ensure that dir() will include files with the given extensions.
The extensions should not have '.' prefixes.
All except 'suppressWarningForExtensions' allow the given kinds of files
to be packaged with their respective semantics (read the source).
'suppressWarningForExtensions' lists extensions *expected* to be ignored,
so no warnings will be emitted for them.
"""
if executableExtensions:
self.executableExtensions += executableExtensions
if extractExtensions:
self.extractExtensions += extractExtensions
if imageExtensions:
self.imageExtensions += imageExtensions
if textExtensions:
self.textExtensions += textExtensions
if uncompressibleExtensions:
self.uncompressibleExtensions += uncompressibleExtensions
if unprocessedExtensions:
self.unprocessedExtensions += unprocessedExtensions
if suppressWarningForExtensions:
self.suppressWarningForExtensions += suppressWarningForExtensions
self._ensureExtensions()
def do_dir(self, dirname, newDir = None, unprocessed = None):
""" Adds the indicated directory hierarchy to the current
@ -3676,7 +3757,12 @@ class Packager:
filename.setBinary()
self.currentPackage.addFile(filename, newName = newName,
explicit = False, unprocessed = unprocessed)
elif not ext in self.suppressWarningForExtensions:
newCount = self.currentPackage.ignoredDirFiles.get(ext, 0) + 1
self.currentPackage.ignoredDirFiles[ext] = newCount
if self.verbosePrint:
self.notify.warning("ignoring file %s" % filename)
def readContentsFile(self):
""" Reads the contents.xml file at the beginning of
@ -3750,8 +3836,7 @@ class Packager:
xhost = he.makeXml(packager = self)
xcontents.InsertEndChild(xhost)
contents = self.contents.items()
contents.sort()
contents = sorted(self.contents.items())
for key, pe in contents:
xpackage = pe.makeXml()
xcontents.InsertEndChild(xpackage)

View File

@ -66,7 +66,7 @@ class images(package):
token = '%s_img' % (name)
configDict[token] = basename
else:
print "Could not locate %s" % (filename)
print("Could not locate %s" % (filename))
# Also make a few special cases. We use the same default image
# for many of the states.

View File

@ -57,6 +57,14 @@ Options:
instead of -e for files that are uncompressible by their nature
(e.g. mpg files). This option may be repeated as necessary.
-x ext
Marks files with the given extensions of needing to be physically
extracted to disk before they can be loaded. This is used for
file types that cannot be loaded via the virtual file system,
such as .ico files on Windows.
This option is currently only implemented when deploying the
application with pdeploy.
-p python_lib_dir
Adds a directory to search for additional Python modules. You
can use this to add your system's Python path, to allow packp3d
@ -103,7 +111,7 @@ class ArgumentError(StandardError):
pass
def makePackedApp(args):
opts, args = getopt.getopt(args, 'o:d:m:S:e:n:p:c:r:s:Dh')
opts, args = getopt.getopt(args, 'o:d:m:S:e:n:x:p:c:r:s:Dh')
packager = Packager.Packager()
@ -134,6 +142,8 @@ def makePackedApp(args):
packager.binaryExtensions.append(value)
elif option == '-n':
packager.uncompressibleExtensions.append(value)
elif option == '-x':
packager.extractExtensions.append(value)
elif option == '-p':
sys.path.append(value)
elif option == '-c':
@ -154,10 +164,10 @@ def makePackedApp(args):
PandaSystem.getPackageHostUrl(),
os.path.split(sys.argv[0])[1],
'%s.%s' % (sys.version_info[0], sys.version_info[1]))
sys.exit(1)
sys.exit(0)
if not appFilename:
raise ArgumentError, "No target app specified. Use:\n%s -o app.p3d" % (os.path.split(sys.argv[0])[1])
raise ArgumentError, "No target app specified. Use:\n %s -o app.p3d\nUse -h to get more usage information." % (os.path.split(sys.argv[0])[1])
if args:
raise ArgumentError, "Extra arguments on command line."
@ -170,19 +180,20 @@ def makePackedApp(args):
appDir = Filename('.')
appBase = appFilename.getBasenameWoExtension()
if not main:
if main:
main = Filename.fromOsSpecific(main)
main.makeAbsolute(root)
else:
main = Filename(root, 'main.py')
if main.exists():
main = 'main.py'
else:
if not main.exists():
main = glob.glob(os.path.join(root.toOsSpecific(), '*.py'))
if len(main) == 0:
raise ArgumentError, 'No Python files in root directory.'
elif len(main) > 1:
raise ArgumentError, 'Multiple Python files in root directory; specify the main application with -m "main".'
main = os.path.split(main[0])[1]
main = Filename.fromOsSpecific(main)
main = Filename.fromOsSpecific(os.path.split(main[0])[1])
main.makeAbsolute(root)
packager.installDir = appDir
packager.allowPythonDev = allowPythonDev

View File

@ -61,7 +61,7 @@ class panda3d(package):
'panda3d.physics')
# Include various standard Python encodings. The rest is in morepy.
module('encodings', 'encodings.aliases', 'encodings.undefined,'
module('encodings', 'encodings.aliases', 'encodings.undefined',
'encodings.utf_8', 'encodings.ascii', 'encodings.string_escape',
'encodings.mbcs', 'encodings.latin_1', 'io')
@ -195,7 +195,7 @@ class morepy(package):
'termios', 'tty', 'pty', 'fcntl', 'pipes', 'posixfile',
'resource', 'nis', 'syslog', 'commands', 'ic', 'MacOS',
'macostools', 'findertools', 'EasyDialogs', 'FrameWork',
'autoGIL', 'ColorPicker')
'autoGIL', 'ColorPicker', 'ast')
# To add the multitude of standard Python string encodings.
module('encodings', 'encodings.*')
@ -362,8 +362,16 @@ class rocket(package):
config(display_name = "Panda3D libRocket support")
require('panda3d')
module('panda3d.rocket', required = True)
module('_rocketcore', '_rocketcontrols')
file('rocket.py', extract = True, text = """
from _rocketcore import *
try:
from _rocketcontrols import *
except ImportError:
pass
""")
module('panda3d.rocket', '_rocketcore', required = True)
module('_rocketcontrols')
file('libp3rocket.dll', required = True)
class vrpn(package):

View File

@ -123,6 +123,10 @@ Options:
as such. This only applies to .p3d packages, not to other types
of packages!
-v
Emit a warning for any file not recognized by the dir() command
(indicating there may be a need for addExtensions(...)).
-h
Display this help
"""
@ -135,12 +139,12 @@ from direct.p3d import Packager
from panda3d.core import *
def usage(code, msg = ''):
print >> sys.stderr, usageText % {
sys.stderr.write(usageText % {
'version' : PandaSystem.getPackageVersionString(),
'host' : PandaSystem.getPackageHostUrl(),
'prog' : os.path.split(sys.argv[0])[1]
}
print >> sys.stderr, msg
})
sys.stderr.write(msg + '\n')
sys.exit(code)
installDir = None
@ -151,12 +155,13 @@ allowPythonDev = False
universalBinaries = False
systemRoot = None
ignoreSetHost = False
verbosePrint = False
p3dSuffix = ''
platforms = []
try:
opts, args = getopt.getopt(sys.argv[1:], 'i:ps:S:DuP:R:Ha:h')
except getopt.error, msg:
opts, args = getopt.getopt(sys.argv[1:], 'i:ps:S:DuP:R:Ha:hv')
except getopt.error as msg:
usage(1, msg)
for opt, arg in opts:
@ -188,10 +193,13 @@ for opt, arg in opts:
elif opt == '-a':
p3dSuffix = arg
elif opt == '-v':
verbosePrint = True
elif opt == '-h':
usage(0)
else:
print 'illegal option: ' + arg
print('illegal option: ' + arg)
sys.exit(1)
if not args:
@ -212,7 +220,7 @@ else:
if universalBinaries:
if platforms:
print '\nYou may not specify both -u and -P.\n'
print('\nYou may not specify both -u and -P.\n')
sys.exit(1)
if PandaSystem.getPlatform().startswith('osx_'):
platforms = ['osx_i386', 'osx_amd64']
@ -230,6 +238,7 @@ for platform in platforms:
packager.allowPythonDev = allowPythonDev
packager.systemRoot = systemRoot
packager.ignoreSetHost = ignoreSetHost
packager.verbosePrint = verbosePrint
packager.p3dSuffix = p3dSuffix
try:
@ -242,7 +251,7 @@ for platform in platforms:
except Packager.PackagerError:
# Just print the error message and exit gracefully.
inst = sys.exc_info()[1]
print inst.args[0]
print(inst.args[0])
sys.exit(1)
# An explicit call to exit() is required to exit the program, when

View File

@ -137,7 +137,7 @@ class pyopengl(package):
module('OpenGL.GLU', 'OpenGL.GLUT', 'OpenGL.GLE', 'OpenGL.GLX')
class httplib2(package):
config(display_name = "httplib2")
config(display_name = "httplib2", platform_specific = False)
require('panda3d')
module('httplib2', required = True)
@ -149,7 +149,7 @@ class box2d(package):
module('Box2D', required = True)
class pyglet(package):
config(display_name = "pyglet")
require('panda3d')
config(display_name = "pyglet", platform_specific = False)
require('panda3d', 'morepy')
module('pyglet', required = True)

View File

@ -2,8 +2,8 @@
if __name__ == "__main__":
from direct.directbase.TestStart import *
from pandac.LinearVectorForce import LinearVectorForce
from pandac.Vec3 import Vec3
from panda3d.physics import LinearVectorForce
from panda3d.core import Vec3
import ParticleEffect
from direct.tkpanels import ParticlePanel
import Particles

View File

@ -140,7 +140,7 @@ load_plugin(const string &p3d_plugin_filename,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir,
ostream &logfile) {
const string &start_dir, ostream &logfile) {
if (plugin_loaded) {
return true;
}
@ -259,7 +259,7 @@ load_plugin(const string &p3d_plugin_filename,
verify_contents, platform,
log_directory, log_basename,
trusted_environment, console_environment,
root_dir, host_dir, logfile)) {
root_dir, host_dir, start_dir, logfile)) {
unload_dso();
return false;
}
@ -283,7 +283,7 @@ init_plugin(const string &contents_filename, const string &host_url,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir,
ostream &logfile) {
const string &start_dir, ostream &logfile) {
// Ensure that all of the function pointers have been found.
if (P3D_initialize_ptr == NULL ||
@ -371,15 +371,26 @@ init_plugin(const string &contents_filename, const string &host_url,
return false;
}
if (!P3D_initialize_ptr(P3D_API_VERSION, contents_filename.c_str(),
// A bit of extra hand-hacked compatibility for using newer plug-ins
// with an older version of the core API.
int api_version = P3D_API_VERSION;
if (api_version == 17 && start_dir.empty()) {
api_version = 16;
if (host_dir.empty()) {
api_version = 15;
}
}
if (!P3D_initialize_ptr(api_version, contents_filename.c_str(),
host_url.c_str(), verify_contents, platform.c_str(),
log_directory.c_str(), log_basename.c_str(),
trusted_environment, console_environment,
root_dir.c_str(), host_dir.c_str())) {
root_dir.c_str(), host_dir.c_str(),
start_dir.c_str())) {
// Oops, failure to initialize.
logfile
<< "Failed to initialize plugin (passed API version "
<< P3D_API_VERSION << ")\n";
<< api_version << ")\n";
return false;
}

View File

@ -67,13 +67,15 @@ load_plugin(const string &p3d_plugin_filename,
P3D_verify_contents verify_contents, const string &platform,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir, ostream &logfile);
const string &root_dir, const string &host_dir,
const string &start_dir, ostream &logfile);
bool
init_plugin(const string &contents_filename, const string &host_url,
P3D_verify_contents verify_contents, const string &platform,
const string &log_directory, const string &log_basename,
bool trusted_environment, bool console_environment,
const string &root_dir, const string &host_dir, ostream &logfile);
const string &root_dir, const string &host_dir,
const string &start_dir, ostream &logfile);
void unload_plugin(ostream &logfile);
bool is_plugin_loaded();

View File

@ -163,7 +163,7 @@ start_p3dcert() {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_start_dir = inst_mgr->get_root_dir() + "/start";
_start_dir = inst_mgr->get_start_dir();
string root_dir = _inst->_p3dcert_package->get_package_dir();
mkdir_complete(_start_dir, nout);
@ -183,7 +183,7 @@ start_p3dcert() {
// These are the enviroment variables we forward from the current
// environment, if they are set.
const wchar_t *keep[] = {
L"TMP", L"TEMP", L"HOME", L"USER",
L"TMP", L"TEMP", L"HOME", L"USER",
L"SYSTEMROOT", L"USERPROFILE", L"COMSPEC",
NULL
};
@ -209,7 +209,8 @@ start_p3dcert() {
// These are the enviroment variables we forward from the current
// environment, if they are set.
const char *keep[] = {
"TMP", "TEMP", "HOME", "USER",
"TMP", "TEMP", "HOME", "USER",
"LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG",
#ifdef HAVE_X11
"DISPLAY", "XAUTHORITY",
#endif

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "p3dCert.h"
#include "p3dCert_strings.h"
#include "wstring_encode.h"
#include "mkdir_complete.h"
@ -26,8 +27,9 @@
#include <sys/stat.h>
#include <string.h>
#include <limits.h>
#include <locale.h>
#define BUTTON_WIDTH 120
#define BUTTON_WIDTH 180 // fit the Russian text
#define BUTTON_SPACE 10
#include "ca_bundle_data_src.c"
@ -36,63 +38,152 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <malloc.h>
#define snprintf sprintf_s
#endif
static const char
self_signed_cert_text[] =
"This Panda3D application uses a self-signed certificate. "
"This means the author's name can't be verified, and you have "
"no way of knowing for sure who wrote it.\n\n"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
"We recommend you click Cancel to avoid running this application.";
static LanguageIndex li = LI_default;
static const char
unknown_auth_cert_text[] =
"This Panda3D application has been signed, but we don't recognize "
"the authority that verifies the signature. This means the author's "
"name can't be trusted, and you have no way of knowing "
"for sure who wrote it.\n\n"
#if defined(_WIN32)
static LanguageIndex detect_language() {
// This function was introduced in Windows Vista; it may not be available
// on older systems.
typedef BOOL (*GUPL)(DWORD, PULONG, PZZWSTR, PULONG);
GUPL pGetUserPreferredUILanguages = (GUPL)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
TEXT("GetUserPreferredUILanguages"));
if (pGetUserPreferredUILanguages != NULL) {
ULONG num_langs = 0;
ULONG buffer_size = 0;
pGetUserPreferredUILanguages(8, &num_langs, NULL, &buffer_size);
PZZWSTR buffer = (PZZWSTR)_alloca(buffer_size);
if (pGetUserPreferredUILanguages(8, &num_langs, buffer, &buffer_size)) {
for (ULONG i = 0; i < num_langs; ++i) {
size_t len = wcslen(buffer);
if (len >= 2 && (buffer[2] == 0 || buffer[2] == L'-')) {
// It may be a two-letter code; match it in our list.
for (int j = 0; j < LI_COUNT; ++j) {
const char *lang_code = language_codes[j];
if (lang_code != NULL && lang_code[0] == buffer[0] &&
lang_code[1] == buffer[1]) {
return (LanguageIndex)j;
}
}
}
buffer += len + 1;
}
}
}
"We recommend you click Cancel to avoid running this application.";
// Fall back to the old Windows XP function.
LANGID lang = GetUserDefaultUILanguage() & 0x3ff;
if (lang == 0) {
return LI_default;
}
static const char
verified_cert_text[] =
"This Panda3D application has been signed by %s. "
"If you trust %s, then click the Run button below "
"to run this application on your computer. This will also "
"automatically approve this and any other applications signed by "
"%s in the future.\n\n"
for (int i = 0; i < LI_COUNT; ++i) {
if (language_ids[i] != 0 && language_ids[i] == lang) {
return (LanguageIndex)i;
}
}
return LI_default;
}
"If you are unsure about this application, "
"you should click Cancel instead.";
#elif defined(__APPLE__)
static LanguageIndex detect_language() {
// Get and iterate through the list of preferred languages.
CFArrayRef langs = CFLocaleCopyPreferredLanguages();
CFIndex num_langs = CFArrayGetCount(langs);
static const char
expired_cert_text[] =
"This Panda3D application has been signed by %s, "
"but the certificate has expired.\n\n"
for (long i = 0; i < num_langs; ++i) {
CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(langs, i);
"You should check the current date set on your computer's clock "
"to make sure it is correct.\n\n"
CFIndex length = CFStringGetLength(lang);
if (length < 2) {
continue;
}
"If your computer's date is correct, we recommend "
"you click Cancel to avoid running this application.";
CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buffer = (char *)alloca(max_size);
if (!CFStringGetCString(lang, buffer, max_size, kCFStringEncodingUTF8)) {
continue;
}
static const char
generic_error_cert_text[] =
"This Panda3D application has been signed, but there is a problem "
"with the certificate (OpenSSL error code %d).\n\n"
if (isalnum(buffer[2])) {
// It's not a two-letter code.
continue;
}
"We recommend you click Cancel to avoid running this application.";
// See if we support this language.
for (int j = 0; j < LI_COUNT; ++j) {
const char *lang_code = language_codes[j];
if (lang_code != NULL && strncasecmp(buffer, lang_code, 2) == 0) {
CFRelease(langs);
return (LanguageIndex)j;
}
}
}
static const char
no_cert_text[] =
"This Panda3D application has not been signed. This means you have "
"no way of knowing for sure who wrote it.\n\n"
CFRelease(langs);
return LI_default;
}
"Click Cancel to avoid running this application.";
#else
static LanguageIndex detect_language() {
// First consult the LANGUAGE variable, which is a GNU extension that can
// contain multiple languages in order of preference.
const char *lang = getenv("LANGUAGE");
while (lang != NULL && lang[0] != 0) {
size_t len;
const char *next = strchr(lang, ':');
if (next == NULL) {
len = strlen(lang);
} else {
len = (next - lang);
++next;
}
if (len >= 2 && !isalnum(lang[2])) {
// It may be a two-letter language code; match it in our list.
for (int i = 0; i < LI_COUNT; ++i) {
const char *lang_code = language_codes[i];
if (lang_code != NULL && strncasecmp(lang, lang_code, 2) == 0) {
return (LanguageIndex)i;
}
}
}
lang = next;
}
// Fall back to the C locale functions.
setlocale(LC_ALL, "");
lang = setlocale(LC_MESSAGES, NULL);
if (lang == NULL || lang[0] == 0 || strcmp(lang, "C") == 0) {
// Try the LANG variable.
lang = getenv("LANG");
}
if (lang == NULL || strlen(lang) < 2 || isalnum(lang[2])) {
// Couldn't extract a meaningful two-letter code.
return LI_default;
}
// It may be a two-letter language code; match it in our list.
for (int i = 0; i < LI_COUNT; ++i) {
const char *lang_code = language_codes[i];
if (lang_code != NULL && strncasecmp(lang, lang_code, 2) == 0) {
return (LanguageIndex)i;
}
}
return LI_default;
}
#endif
#ifdef _WIN32
int WINAPI
@ -107,6 +198,8 @@ wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdS
return 1;
}
li = detect_language();
wstring cert_filename (argv[0]);
wstring cert_dir (argv[1]);
LocalFree(argv);
@ -126,6 +219,8 @@ int main(int argc, char **argv) {
return 1;
}
li = detect_language();
string cert_filename (argv[1]);
string cert_dir (argv[2]);
@ -148,7 +243,7 @@ AuthDialog(const wstring &cert_filename, const wstring &cert_dir) :
AuthDialog::
AuthDialog(const string &cert_filename, const string &cert_dir) :
#endif
Fl_Window(435, 242, "New Panda3D Application"),
Fl_Window(435, 242, new_application_title[li]),
_cert_dir(cert_dir)
{
_view_cert_dialog = NULL;
@ -315,12 +410,20 @@ read_cert_file(const string &cert_filename) {
#endif // _WIN32
if (fp == NULL) {
#ifdef _WIN32
wcerr << L"Couldn't read " << cert_filename.c_str() << L"\n";
#else
cerr << "Couldn't read " << cert_filename.c_str() << "\n";
#endif
return;
}
_cert = PEM_read_X509(fp, NULL, NULL, (void *)"");
if (_cert == NULL) {
#ifdef _WIN32
wcerr << L"Could not read certificate in " << cert_filename.c_str() << L".\n";
#else
cerr << "Could not read certificate in " << cert_filename.c_str() << ".\n";
#endif
fclose(fp);
return;
}
@ -510,19 +613,19 @@ layout() {
short bx = (w() - nbuttons * BUTTON_WIDTH - (nbuttons - 1) * BUTTON_SPACE) / 2;
if (_verify_result == 0 && _cert != NULL) {
Fl_Return_Button *run_button = new Fl_Return_Button(bx, next_y, BUTTON_WIDTH, 25, "Run");
Fl_Return_Button *run_button = new Fl_Return_Button(bx, next_y, BUTTON_WIDTH, 25, run_title[li]);
run_button->callback(this->run_clicked, this);
bx += BUTTON_WIDTH + BUTTON_SPACE;
}
if (_cert != NULL) {
Fl_Button *view_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, "View Certificate");
Fl_Button *view_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, show_cert_title[li]);
view_button->callback(this->view_cert_clicked, this);
bx += BUTTON_WIDTH + BUTTON_SPACE;
}
Fl_Button *cancel_button;
cancel_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, "Cancel");
cancel_button = new Fl_Button(bx, next_y, BUTTON_WIDTH, 25, cancel_title[li]);
cancel_button->callback(this->cancel_clicked, this);
next_y += 42;
@ -542,12 +645,12 @@ void AuthDialog::
get_text(char *header, size_t hlen, char *text, size_t tlen) {
switch (_verify_result) {
case -1:
strncpy(header, "No signature!", hlen);
strncpy(text, no_cert_text, tlen);
strncpy(header, no_cert_title[li], hlen);
strncpy(text, no_cert_text[li], tlen);
break;
case 0:
snprintf(text, tlen, verified_cert_text, _friendly_name.c_str(),
snprintf(text, tlen, verified_cert_text[li], _friendly_name.c_str(),
_friendly_name.c_str(), _friendly_name.c_str());
break;
@ -555,24 +658,24 @@ get_text(char *header, size_t hlen, char *text, size_t tlen) {
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CRL_HAS_EXPIRED:
strncpy(header, "Expired signature!", hlen);
snprintf(text, tlen, expired_cert_text, _friendly_name.c_str());
strncpy(header, expired_cert_title[li], hlen);
snprintf(text, tlen, expired_cert_text[li], _friendly_name.c_str());
break;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
strncpy(header, "Unverified signature!", hlen);
snprintf(text, tlen, unknown_auth_cert_text);
strncpy(header, unverified_cert_title[li], hlen);
strncpy(text, unknown_auth_cert_text[li], tlen);
break;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
strncpy(header, "Unverified signature!", hlen);
strncpy(text, self_signed_cert_text, tlen);
strncpy(header, unverified_cert_title[li], hlen);
strncpy(text, self_signed_cert_text[li], tlen);
break;
default:
strncpy(header, "Unverified signature!", hlen);
snprintf(text, tlen, generic_error_cert_text, _verify_result);
strncpy(header, unverified_cert_title[li], hlen);
snprintf(text, tlen, generic_error_cert_text[li], _verify_result);
}
}
@ -583,7 +686,7 @@ get_text(char *header, size_t hlen, char *text, size_t tlen) {
////////////////////////////////////////////////////////////////////
ViewCertDialog::
ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) :
Fl_Window(600, 400, "View Certificate"),
Fl_Window(600, 400, show_cert_title[li]),
_auth_dialog(auth_dialog),
_cert(cert)
{
@ -660,12 +763,12 @@ layout() {
short bx = (w() - BUTTON_WIDTH * 2 - BUTTON_SPACE) / 2;
Fl_Return_Button *run_button = new Fl_Return_Button(bx, 360, BUTTON_WIDTH, 25, "Run");
Fl_Return_Button *run_button = new Fl_Return_Button(bx, 360, BUTTON_WIDTH, 25, run_title[li]);
run_button->callback(this->run_clicked, this);
bx += BUTTON_WIDTH + BUTTON_SPACE;
Fl_Button *cancel_button = new Fl_Button(bx, 360, BUTTON_WIDTH, 25, "Cancel");
Fl_Button *cancel_button = new Fl_Button(bx, 360, BUTTON_WIDTH, 25, cancel_title[li]);
cancel_button->callback(this->cancel_clicked, this);
end();

View File

@ -92,9 +92,9 @@ private:
X509 *_cert;
STACK_OF(X509) *_stack;
char _header[32];
char _text[512];
char _text_clean[1024];
char _header[64];
char _text[1024];
char _text_clean[2048];
string _friendly_name;
int _verify_result;

View File

@ -0,0 +1,571 @@
// Filename: p3dCert_strings.h
// Created by: rdb (25Mar15)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "p3dCert_strings.h"
// Translations kindly provided by:
// eng: drwr
// nld: rdb
// deu: Sebastian Hoffmann <TheCheapestPixels at googlemail dot com>
// spa: Imanol Celaya <imanol at celaya dot me>
// ita: Flavio Clava
// rus: montreal
const char *language_codes[LI_COUNT] =
{"en", "nl", "de", "es", "it", "eo", "ru"};
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd318693%28v=vs.85%29.aspx
const unsigned char language_ids[LI_COUNT] =
{0x09, 0x13, 0x07, 0x0A, 0x10, 0x8F, 0x19};
const char *
run_title[LI_COUNT] = {
"Run",
"Uitvoeren",
"Starten",
"Ejecutar",
"Lancia",
"Lan\304\211i",
"\320\227\320\260\320\277\321\203\321\201\321\202\320\270\321\202\321\214",
};
const char *
cancel_title[LI_COUNT] = {
"Cancel",
"Annuleren",
"Abbrechen",
"Cancelar",
"Cancella",
"Nuligi",
"\320\236\321\202\320\274\320\265\320\275\320\260",
};
const char *
show_cert_title[LI_COUNT] = {
"Show Certificate",
"Toon Certificaat",
"Zertifikat anzeigen",
"Mostrar certificado",
"Mostra certificato",
"Montri Ateston",
"\320\237\320\276\320\272\320\260\320\267\320\260\321\202\321\214 \321\201"
"\320\265\321\200\321\202\320\270\321\204\320\270\320\272\320\260\321\202",
};
const char *
new_application_title[LI_COUNT] = {
"New Panda3D Application",
"Nieuwe Panda3D Applicatie",
"Neue Panda3D-Anwendung",
"Nueva aplicaci\303\263n de Panda3D",
"Nuova applicazione Panda3D",
"Nova aplika\304\265o de Panda3D",
"\320\235\320\276\320\262\320\276\320\265 Panda3D-\320\277\321\200\320\270"
"\320\273\320\276\320\266\320\265\320\275\320\270\320\265",
};
const char *
no_cert_title[LI_COUNT] = {
"No signature!",
"Geen handtekening!",
"Keine Signatur!",
"Sin firma!",
"Nessuna firma!",
"Neniu subskribo!",
"\320\235\320\265\321\202 \320\277\320\276\320\264\320\277\320\270\321\201"
"\320\270!",
};
const char *
unverified_cert_title[LI_COUNT] = {
"Unverified signature!",
"Ongeverifieerde handtekening!",
"Unbest\303\244tigte Signatur!",
"Firma sin verificar!",
"Firma non verificata!",
"Nekontrolita subskribo!",
"\320\235\320\265\320\277\321\200\320\276\320\262\320\265\321\200\320\265"
"\320\275\320\275\320\260\321\217 \320\277\320\276\320\264\320\277\320\270"
"\321\201\321\214!",
};
const char *
expired_cert_title[LI_COUNT] = {
"Expired signature!",
"Verlopen handtekening!",
"Abgelaufene Signatur!",
"Firma caducada!",
"Firma scaduta!",
"Eksvalidi\304\235inta subskribo!",
"\320\241\321\200\320\276\320\272 \320\264\320\265\320\271\321\201\321\202"
"\320\262\320\270\321\217 \320\277\320\276\320\264\320\277\320\270\321\201"
"\320\270 \320\270\321\201\321\202\321\221\320\272!",
};
const char *
self_signed_cert_text[LI_COUNT] = {
// eng
"This Panda3D application uses a self-signed certificate. "
"This means the author's name can't be verified, and you have "
"no way of knowing for sure who wrote it.\n"
"\n"
"We recommend you click Cancel to avoid running this application.",
// nld
"Deze Panda3D applicatie gebruikt een zelf-getekend certificaat. "
"Dit betekent dat de auteursnaam niet kan worden geverifieerd, en het "
"niet zeker is of de applicatie te vertrouwen is.\n"
"\n"
"Het is aanbevolen om op Annuleren te klikken om de applicatie af te "
"sluiten.",
// deu
"Diese Panda3D-Anwendung benutzt ein selbst-signiertes Zertifikat. Dies "
"bedeutet, dass weder der Name des Autors \303\274berpr\303\274ft werden "
"kann, noch dass garantiert werden kann, dass tats\303\244chlich die "
"angegebene Person diese Anwendung geschrieben hat.\n"
"\n"
"Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht "
"auszuf\303\274hren.",
// spa
"Esta aplicaci\303\263n de Panda3D usa un certificado autofirmado. "
"Esto significa que el nombre del autor no puede ser verificado y no se "
"puede conocer seguro quien la ha escrito.\n"
"\n"
"Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.",
// ita
"Questa applicazione Panda3D usa un certificato autofirmato. Ci\303\262 "
"significa che il nome dell'autore non pu\303\262 essere verificato, e "
"che non hai modo di assicurarti circa chi la abbia scritta.\n"
"\n"
"Raccomandiamo di cliccare su Cancella per evitare di lanciare questa "
"applicazione.",
// epo
"\304\210i tiu aplika\304\265o de Panda3D uzas memsubskribitan ateston. "
"Tio signifas ke la nomo de la verkanto ne povas esti kontrolita, kaj vi "
"ne havas certan scimanieron pri la vera verkanto de la aplika\304\265o.\n"
"\n"
"Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on de "
"\304\211i tiu aplika\304\265o.",
// rus
"\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266"
"\320\265\320\275\320\270\320\265 \320\270\321\201\320\277\320\276\320\273"
"\321\214\320\267\321\203\320\265\321\202 \321\201\320\260\320\274\320\276"
"\320\267\320\260\320\262\320\265\321\200\320\265\320\275\320\275\321\213"
"\320\271 \321\201\320\265\321\200\321\202\320\270\321\204\320\270\320\272"
"\320\260\321\202. \320\255\321\202\320\276 \320\276\320\267\320\275"
"\320\260\321\207\320\260\320\265\321\202, \321\207\321\202\320\276 "
"\320\270\320\274\321\217 \320\260\320\262\321\202\320\276\321\200\320\260 "
"\320\275\320\265 \320\274\320\276\320\266\320\265\321\202 \320\261\321\213"
"\321\202\321\214 \320\277\320\276\320\264\321\202\320\262\320\265\320\266"
"\320\264\320\265\320\275\320\276, \320\270 \320\262\321\213 \320\275"
"\320\265 \320\274\320\276\320\266\320\265\321\202\320\265 \320\267\320\275"
"\320\260\321\202\321\214, \320\272\321\202\320\276 \320\275\320\260"
"\320\277\320\270\321\201\320\260\320\273 \321\215\321\202\320\276 \320\277"
"\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.\n"
"\n"
"\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275"
"\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260"
"\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265"
"\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277"
"\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 "
"\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270"
"\320\265.",
};
const char *
unknown_auth_cert_text[LI_COUNT] = {
"This Panda3D application has been signed, but we don't recognize "
"the authority that verifies the signature. This means the author's "
"name can't be verified, and you have no way of knowing "
"for sure who wrote it.\n"
"\n"
"We recommend you click Cancel to avoid running this application.",
// nld
"Deze Panda3D applicatie is ondertekend, maar de certificaatautoriteit "
"die het certificaat heeft uitgegeven wordt niet herkend. Dit betekent "
"dat de auteursnaam niet te vertrouwen is, en het niet zeker is wie de "
"applicatie gemaakt heeft.\n"
"\n"
"Het is aanbevolen om op Annuleren te klikken om de applicatie af te "
"sluiten.",
// deu
"Diese Panda3D-Anwendung wurde signiert, aber die "
"\303\234berpr\303\274fungsstelle wurde nicht anerkannt. Dies bedeutet, "
"dass weder der Name des Autors \303\274berpr\303\274ft werden kann, noch "
"dass garantiert werden kann, dass tats\303\244chlich die angegebene "
"Person diese Anwendung geschrieben hat.\n"
"\n"
"Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht "
"auszuf\303\274hren.",
// spa
"Esta aplicaci\303\263n de Panda3D esta firmada, pero no reconocemos la "
"autoridad que la verifica. Esto significa que el nombre del autor no "
"puede ser verificado y no se puede conocer seguro quien la ha escrito.\n"
"\n"
"Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.",
// ita
"Questa applicazione Panda3D \303\250 stata firmata, ma non riconosciamo "
"l'autorit\303\240 che verifica la firma. Ci\303\262 significa che il "
"nome dell'autore non pu\303\262 essere verificato, e che non hai modo "
"di assicurarti circa chi la abbia scritta.\n"
"\n"
"Raccomandiamo di cliccare su Cancella per evitare di lanciare questa "
"applicazione.",
// epo
"\304\210i tiu aplika\304\265o estas subskribita, sed ni ne rekonas "
"la a\305\255toritaton, kiu kontrolas la subskribon. Tio signifas ke la "
"nomo de la verkanto ne povas esti konfidata, kaj vi ne havas certan "
"scimanieron pri la vera verkanto de la aplika\304\265o.\n"
"\n"
"Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on "
"de \304\211i tiu aplika\304\265o.",
// rus
"\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270"
"\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\265\321\201"
"\321\202\321\214 \320\277\320\276\320\264\320\277\320\270\321\201\321\214,"
" \320\277\320\276 \320\272\320\276\321\202\320\276\321\200\320\276\320\271"
" \320\274\321\213 \320\275\320\265 \320\274\320\276\320\266\320\265"
"\320\274 \321\200\320\260\321\201\320\277\320\276\320\267\320\275\320\260"
"\321\202\321\214 \320\262\320\273\320\260\320\264\320\265\320\273\321\214"
"\321\206\320\260. \320\255\321\202\320\276 \320\276\320\267\320\275"
"\320\260\321\207\320\260\320\265\321\202, \321\207\321\202\320\276 "
"\320\270\320\274\321\217 \320\260\320\262\321\202\320\276\321\200\320\260 "
"\320\275\320\265 \320\274\320\276\320\266\320\265\321\202 \320\261\321\213"
"\321\202\321\214 \320\276\320\277\321\200\320\265\320\264\320\265\320\273"
"\320\265\320\275\320\276, \320\270 \320\275\320\265\320\262\320\276"
"\320\267\320\274\320\276\320\266\320\275\320\276 \321\202\320\276\321\207"
"\320\275\320\276 \321\203\320\267\320\275\320\260\321\202\321\214, "
"\320\272\321\202\320\276 \320\275\320\260\320\277\320\270\321\201\320\260"
"\320\273 \321\215\321\202\320\276 \320\277\321\200\320\270\320\273\320\276"
"\320\266\320\265\320\275\320\270\320\265.\n"
"\n"
"\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275"
"\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260"
"\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265"
"\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277"
"\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 "
"\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270"
"\320\265.",
};
const char *
verified_cert_text[LI_COUNT] = {
// eng
"This Panda3D application has been signed by %s. "
"If you trust %s, then click the Run button below "
"to run this application on your computer. This will also "
"automatically approve this and any other applications signed by "
"%s in the future.\n"
"\n"
"If you are unsure about this application, "
"you should click Cancel instead.",
// nld
"Deze Panda3D applicatie is ondertekend door %s. "
"Als u %s vertrouwt, klik dan de onderstaande knop Uitvoeren om de applicatie "
"op uw computer uit te voeren. Dit zal ook deze en andere door %s getekende "
"applicaties in het vervolg toestaan.\n"
"\n"
"Als u niet zeker bent over deze applicatie is het aanbevolen om op "
"Annuleren te klikken.",
// deu
"Diese Panda3D-Anwendung wurde von %s signiert. Falls Sie %s vertrauen, "
"dr\303\274cken Sie den Starten-Knopf, um diese Anwendung auszuf\303\274hren. "
"Zudem werden in der Zukunft diese und alle anderen von %s signierten "
"Anwendungen automatisch als vertrauensw\303\274rdig anerkannt.\n"
"\n"
"Falls Sie sich unsicher \303\274ber diese Anwendung sind, sollten Sie "
"Abbrechen dr\303\274cken.",
// spa
"Esta aplicaci\303\263n de Panda3D ha sido firmada por %s. Si se considera %s"
"de confianza el bot\303\263n inferior ejecutar\303\241 la aplicaci\303\263n."
"Esto validara esta y cualquier otra applizacion firmada por %s en el futuro.\n"
"\n"
"Si se duda de la aplicaci\303\263nse recomienda cancelar."
// ita
"Questa applicazione Panda3D \303\250 stata firmata da %s. Se %s \303\250 "
"un'entit\303\240 fidata, allora clicca il bottone Lancia sottostante per "
"lanciare questa applicazione sul tuo computer. Inoltre, ci\303\262 "
"approver\303\240 automaticamente questa e ogni altra applicazione "
"firmata da %s in futuro.\n"
"\n"
"Se non sei sicuro circa questa applicazione, dovresti invece cliccare "
"su Cancella.",
// epo
"\304\210i tiu aplika\304\265o estas subskribita de %s. "
"Se %s estas fidinda la\305\255 vi, premu la butonon 'Lan\304\211i' sube por "
"lan\304\211i \304\211i tiun aplika\304\265on per via komputilo. Anka\305\255 "
"tio a\305\255tomate estonece aprobos \304\211i tiun kaj alian ajn "
"aplika\304\265on, kiu estas subskribita de %s.\n"
"\n"
"Se vi ne estas certa pri \304\211i tiu aplika\304\265o, "
"vi anstata\305\255e povus premi la butonon 'Nuligi'.",
// rus
"\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266"
"\320\265\320\275\320\270\320\265 \320\277\320\276\320\264\320\277\320\270"
"\321\201\320\260\320\275\320\276 %s. "
"\320\225\321\201\320\273\320\270 \320\262\321\213 \320\264\320\276\320\262"
"\320\265\321\200\321\217\320\265\321\202\320\265 %s, \320\275\320\260"
"\320\266\320\274\320\270\321\202\320\265 \320\272\320\275\320\276\320\277"
"\320\272\321\203 \"\320\227\320\260\320\277\321\203\321\201\321\202"
"\320\270\321\202\321\214\" \320\262\320\275\320\270\320\267\321\203, "
"\321\207\321\202\320\276\320\261\321\213 \320\267\320\260\320\277\321\203"
"\321\201\321\202\320\270\321\202\321\214 \321\215\321\202\320\276 \320\277"
"\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265 "
"\320\275\320\260 \320\262\320\260\321\210\320\265\320\274 \320\272\320\276"
"\320\274\320\277\321\214\321\216\321\202\320\265\321\200\320\265. \320\255"
"\321\202\320\276 \321\202\320\260\320\272\320\266\320\265 \320\260\320\262"
"\321\202\320\276\320\274\320\260\321\202\320\270\321\207\320\265\321\201"
"\320\272\320\270 \320\277\320\276\320\264\321\202\320\262\320\265\321\200"
"\320\264\320\270\321\202 \321\215\321\202\320\276 \320\270 \320\264"
"\321\200\321\203\320\263\320\270\320\265 \320\277\321\200\320\270\320\273"
"\320\276\320\266\320\265\320\275\320\270\321\217, \320\275\320\260\320\277"
"\320\270\321\201\320\260\320\275\320\275\321\213\320\265 %s \320\262 "
"\320\261\321\203\320\264\321\203\321\211\320\265\320\274.\n"
"\n"
"\320\225\321\201\320\273\320\270 \320\262\321\213 \320\275\320\265 "
"\321\203\320\262\320\265\321\200\320\265\320\275\321\213 \320\262 \321\215"
"\321\202\320\276\320\274 \320\277\321\200\320\270\320\273\320\276\320\266"
"\320\265\320\275\320\270\320\270, \320\275\320\260\320\266\320\274\320\270"
"\321\202\320\265 \320\272\320\275\320\276\320\277\320\272\321\203 \""
"\320\236\321\202\320\274\320\265\320\275\320\260\".",
};
const char *
expired_cert_text[LI_COUNT] = {
// eng
"This Panda3D application has been signed by %s, "
"but the certificate has expired.\n"
"\n"
"You should check the current date set on your computer's clock "
"to make sure it is correct.\n"
"\n"
"If your computer's date is correct, we recommend "
"you click Cancel to avoid running this application.",
// nld
"Deze Panda3D applicatie is ondertekend door %s, maar de geldigheidsdatum "
"van het certificaat is verstreken.\n"
"\n"
"Controleer de datum op uw computerklok om te zorgen dat deze juist is "
"ingesteld.\n"
"\n"
"Als de datum op uw computer juist is, is het aanbevolen om op Annuleren te "
"klikken om de applicatie af te sluiten.",
// deu
"Diese Anwendung wurde von %s signiert, aber das Zertifikat ist abgelaufen.\n"
"\n"
"Sie sollten die aktuelle Uhrzeit auf Ihrem Computer "
"\303\274berpr\303\274fen, um sicherzugehen, dass sie korrekt ist.\n"
"\n"
"Falls die Uhrzeit auf Ihrem Computer korrekt ist, empfehlen wir Ihnen "
"Abbrechen zu dr\303\274cken.",
// spa
"Esta aplicaci\303\263n Panda3D ha sido firmada por %s pero el certificado ha"
"caducado.\n"
"\n"
"Se recomienda comprobar la fecha del reloj.\n"
"\n"
"Si la fecha del reloj es correcta se recomienda cancelar.",
// ita
"Questa applicazione Panda3D \303\250 stata firmata da %s, ma il "
"certificato \303\250 scaduto.\n"
"\n"
"Dovresti controllare la data attuale impostata nell'orologio del tuo "
"computer per assicurarti che sia corretta.\n"
"\n"
"Se la data del tuo computer \303\250 corretta, raccomandiamo di cliccare "
"Cancella per evitare di lanciare questa applicazione."
// epo
"\304\210i tiu aplika\304\265o de Panda3D estas subskribita de %s, "
"sed la atesto eksvalidi\304\235is.\n"
"\n"
"Vi povus kontroli la aktualan daton, kiu estas agordata sur la horlo\304\235o de "
"via komputilo por certigi ke \304\235i estas korekta.\n"
"\n"
"Se la dato de via komputilo estas korekta, ni rekomendas ke vi premas la "
"butonon 'Nuligi' por eviti lan\304\211on de \304\211i tiu aplika\304\265o.",
// rus
"\320\255\321\202\320\276 \320\277\321\200\320\270\320\273\320\276\320\266"
"\320\265\320\275\320\270\320\265 \320\277\320\276\320\264\320\277\320\270"
"\321\201\320\260\320\275\320\276 %s, \320\276\320\264\320\275\320\260"
"\320\272\320\276 \321\201\321\200\320\276\320\272 \320\264\320\265\320\271"
"\321\201\321\202\320\262\320\270\321\217 \321\201\320\265\321\200\321\202"
"\320\270\321\204\320\270\320\272\320\260\321\202\320\260 \320\270\321\201"
"\321\202\321\221\320\272.\n"
"\n"
"\320\237\321\200\320\276\320\262\320\265\321\200\321\214\321\202\320\265, "
"\320\277\320\276\320\266\320\260\320\273\321\203\320\271\321\201\321\202"
"\320\260, \320\264\320\260\321\202\321\203 \320\275\320\260 \320\262"
"\320\260\321\210\320\265\320\274 \320\272\320\276\320\274\320\277\321\214"
"\321\216\321\202\320\265\321\200\320\265.\n"
"\n"
"\320\225\321\201\320\273\320\270 \320\275\320\260 \320\262\320\260\321\210"
"\320\265\320\274 \320\272\320\276\320\274\320\277\321\214\321\216\321\202"
"\320\265\321\200\320\265 \321\203\321\201\321\202\320\260\320\275\320\276"
"\320\262\320\273\320\265\320\275\320\276 \320\277\321\200\320\260\320\262"
"\320\270\320\273\321\214\320\275\320\276\320\265 \320\262\321\200\320\265"
"\320\274\321\217, \320\274\321\213 \321\200\320\265\320\272\320\276"
"\320\274\320\265\320\275\320\264\321\203\320\265\320\274 \320\262\320\260"
"\320\274 \320\275\320\260\320\266\320\260\321\202\321\214 \320\272\320\275"
"\320\276\320\277\320\272\321\203 \"\320\236\321\202\320\274\320\265"
"\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277"
"\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 "
"\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270"
"\320\265.",
};
const char *
generic_error_cert_text[LI_COUNT] = {
// eng
"This Panda3D application has been signed, but there is a problem "
"with the certificate (OpenSSL error code %d).\n"
"\n"
"We recommend you click Cancel to avoid running this application.",
// nld
"Deze Panda3D applicatie is ondertekend, maar er is een probleem "
"met het certificaat opgetreden (OpenSSL foutcode %d).\n"
"\n"
"Het is aanbevolen om op Annuleren te klikken om de applicatie af te "
"sluiten.",
// deu
"Diese Panda3D-Anwendung wurde signiert, aber es gibt ein Problem mit "
"dem Zertifikat (OpenSSL Fehlercode %d).\n"
"\n"
"Wir empfehlen, dass Sie Abbrechen dr\303\274cken um diese Anwendung nicht "
"auszuf\303\274hren.",
// spa
"Esta aplicaci\303\263n de Panda3D esta firmada pero hay un problema con el "
"certificado (Error de OpenSSL %d).\n"
"\n"
"Se recomienda cancelar para evitar ejecutar esta aplicaci\303\263n.",
// ita
"Questa applicazione Panda3D \303\250 stata firmata, ma c'\303\250 un "
"problema col certificato (codice di errore OpenSSL %s).\n"
"\n"
"Raccomandiamo di cliccare su Cancella per evitare di lanciare questa "
"applicazione.",
// epo
"\304\210i tiu aplika\304\265o de Panda3D estas subskribita, sed la "
"atesto havas problemon (OpenSSL erarkodo %d).\n"
"\n"
"Ni rekomendas ke vi premas la butonon 'Nuligi' por eviti lan\304\211on "
"de \304\211i tiu aplika\304\265o.",
// rus
"\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270"
"\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\265\321\201"
"\321\202\321\214 \320\277\320\276\320\264\320\277\320\270\321\201\321\214,"
" \320\275\320\276 \320\262\320\276\320\267\320\275\320\270\320\272\320\273"
"\320\260 \320\277\321\200\320\276\320\261\320\273\320\265\320\274\320\260 "
"\321\201 \321\201\320\265\321\200\321\202\320\270\321\204\320\270\320\272"
"\320\260\321\202\320\276\320\274 (\320\232\320\276\320\264 \320\276"
"\321\210\320\270\320\261\320\272\320\270 OpenSSL %d).\n"
"\n"
"\320\234\321\213 \321\200\320\265\320\272\320\276\320\274\320\265\320\275"
"\320\264\321\203\320\265\320\274 \320\262\320\260\320\274 \320\275\320\260"
"\320\266\320\260\321\202\321\214 \"\320\236\321\202\320\274\320\265"
"\320\275\320\260\" \320\270 \320\275\320\265 \320\267\320\260\320\277"
"\321\203\321\201\320\272\320\260\321\202\321\214 \321\215\321\202\320\276 "
"\320\277\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270"
"\320\265.",
};
const char *
no_cert_text[LI_COUNT] = {
"This Panda3D application has not been signed. This means you have "
"no way of knowing for sure who wrote it.\n"
"\n"
"Click Cancel to avoid running this application.",
// nld
"Deze Panda3D applicatie is niet ondertekend. Dit betekent dat het niet "
"mogelijk is om de auteur te verifi\303\253ren.\n"
"\n"
"Klik op Annuleren om de applicatie af te sluiten.",
// deu
"Diese Panda3D-Anwendung wurde nicht signiert. Es gibt keine "
"M\303\266glichkeit festzustellen, wer diese entwickelt hat.\n"
"\n"
"Dr\303\274cken Sie Abbrechen, um diese Anwendung nicht auszuf\303\274hren.",
// spa
"Esta aplicaci\303\263n de Panda3D no esta firmada, no hay forma de conocer "
"quien la ha escrito.\n"
"\n"
"Cancelar para evitar ejecutar la aplicaci\303\263n.",
// ita
"Questa applicazione Panda3D non \303\250 stata firmata. Ci\303\262 "
"significa che non hai modo di assicurarti circa chi la abbia scritta.\n"
"\n"
"Clicca Cancella per evitare di lanciare questa applicazione.",
// epo
"\304\210i tiu aplika\304\265o de Panda3D ne estas subskribita. Tio "
"signifas ke vi ne havas certan scimanieron pri la vera verkanto de "
"la aplika\304\265o.\n"
"\n"
"Premu la butonon 'Nuligi' por eviti lan\304\211on de \304\211i tiu "
"aplika\304\265o.",
// rus
"\320\243 \321\215\321\202\320\276\320\263\320\276 \320\277\321\200\320\270"
"\320\273\320\276\320\266\320\265\320\275\320\270\321\217 \320\275\320\265"
"\321\202 \320\277\320\276\320\264\320\277\320\270\321\201\320\270. "
"\320\255\321\202\320\276 \320\276\320\267\320\275\320\260\321\207\320\260"
"\320\265\321\202, \321\207\321\202\320\276 \320\262\321\213 \320\275"
"\320\265 \320\274\320\276\320\266\320\265\321\202\320\265 \320\267\320\275"
"\320\260\321\202\321\214, \320\272\321\202\320\276 \320\265\320\263"
"\320\276 \320\275\320\260\320\277\320\270\321\201\320\260\320\273.\n"
"\n"
"\320\235\320\260\320\266\320\274\320\270\321\202\320\265 \"\320\236"
"\321\202\320\274\320\265\320\275\320\260\", \321\207\321\202\320\276"
"\320\261\321\213 \320\275\320\265 \320\267\320\260\320\277\321\203\321\201"
"\320\272\320\260\321\202\321\214 \320\277\321\200\320\270\320\273\320\276"
"\320\266\320\265\320\275\320\270\320\265.",
};

View File

@ -0,0 +1,45 @@
// Filename: p3dCert_strings.h
// Created by: rdb (25Mar15)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
enum LanguageIndex {
LI_en, // English
LI_nl, // Dutch
LI_de, // German
LI_es, // Spanish
LI_it, // Italian
LI_eo, // Esperanto
LI_ru, // Russian
LI_COUNT,
LI_default = LI_en
};
extern const char *language_codes[LI_COUNT];
extern const unsigned char language_ids[LI_COUNT];
extern const char *run_title[LI_COUNT];
extern const char *cancel_title[LI_COUNT];
extern const char *show_cert_title[LI_COUNT];
extern const char *new_application_title[LI_COUNT];
extern const char *no_cert_title[LI_COUNT];
extern const char *unverified_cert_title[LI_COUNT];
extern const char *expired_cert_title[LI_COUNT];
extern const char *self_signed_cert_text[LI_COUNT];
extern const char *unknown_auth_cert_text[LI_COUNT];
extern const char *verified_cert_text[LI_COUNT];
extern const char *expired_cert_text[LI_COUNT];
extern const char *generic_error_cert_text[LI_COUNT];
extern const char *no_cert_text[LI_COUNT];

View File

@ -1564,7 +1564,7 @@ uninstall_packages() {
if (inst_mgr->get_verify_contents() != P3D_VC_never) {
string start_dir_suffix = get_start_dir_suffix();
if (!start_dir_suffix.empty()) {
string start_dir = inst_mgr->get_root_dir() + "/start" + start_dir_suffix;
string start_dir = inst_mgr->get_start_dir() + start_dir_suffix;
nout << "Cleaning up start directory " << start_dir << "\n";
inst_mgr->delete_directory_recursively(start_dir);
}
@ -2769,6 +2769,7 @@ make_splash_window() {
int r, g, b;
if (parse_color(r, g, b, _fparams.lookup_token("bgcolor"))) {
_splash_window->set_bgcolor(r, g, b);
_splash_window->set_bar_bgcolor(r, g, b);
} else {
nout << "parse failure on bgcolor " << _fparams.lookup_token("bgcolor") << "\n";
}
@ -2781,11 +2782,98 @@ make_splash_window() {
nout << "parse failure on barcolor " << _fparams.lookup_token("barcolor") << "\n";
}
}
if (_fparams.has_token("bar_bgcolor")) {
int r, g, b;
if (parse_color(r, g, b, _fparams.lookup_token("bar_bgcolor"))) {
_splash_window->set_bar_bgcolor(r, g, b);
} else {
nout << "parse failure on bar_bgcolor " << _fparams.lookup_token("bar_bgcolor") << "\n";
}
}
if (_fparams.has_token("bar_border")) {
int border = _fparams.lookup_token_int("bar_border");
_splash_window->set_bar_border(border);
}
if (_fparams.has_token("bar_bottom")) {
int bottom = _fparams.lookup_token_int("bar_bottom");
_splash_window->set_bar_bottom(bottom);
}
if (_fparams.has_token("bar_width")) {
string bar_width = _fparams.lookup_token("bar_width");
char *endptr;
long width = strtol(bar_width.c_str(), &endptr, 10);
bool percent = false;
if (*endptr == '%') {
percent = true;
++endptr;
}
if (*endptr == '\0' && width >= 0 && width < 65536) {
_splash_window->set_bar_width((int)width, percent);
} else {
nout << "parse failure on bar_width " << bar_width << "\n";
}
}
if (_fparams.has_token("bar_height")) {
string bar_height = _fparams.lookup_token("bar_height");
char *endptr;
long height = strtol(bar_height.c_str(), &endptr, 10);
bool percent = false;
if (*endptr == '%') {
percent = true;
++endptr;
}
if (*endptr == '\0' && height >= 0 && height < 65536) {
_splash_window->set_bar_height((int)height, percent);
} else {
nout << "parse failure on bar_height " << bar_height << "\n";
}
}
if (_fparams.has_token("font_family")) {
string family = _fparams.lookup_token("font_family");
_splash_window->set_font_family(family);
}
if (_fparams.has_token("font_size")) {
int size = _fparams.lookup_token_int("font_size");
_splash_window->set_font_size(size);
}
if (_fparams.has_token("font_style")) {
string style = _fparams.lookup_token("font_style");
if (style == "normal") {
_splash_window->set_font_style(P3DSplashWindow::FS_normal);
} else if (style == "oblique") {
_splash_window->set_font_style(P3DSplashWindow::FS_oblique);
} else if (style == "italic") {
_splash_window->set_font_style(P3DSplashWindow::FS_italic);
} else {
nout << "parse_failure on font_style " << style << "\n";
}
}
if (_fparams.has_token("font_weight")) {
string weight = _fparams.lookup_token("font_weight");
if (weight == "normal") {
_splash_window->set_font_weight(400);
} else if (weight == "bold") {
_splash_window->set_font_weight(700);
} else if (weight == "bolder") {
_splash_window->set_font_weight(700);
} else if (weight == "lighter") {
_splash_window->set_font_weight(100);
} else if (weight.size() == 3 &&
weight[0] >= '1' && weight[0] <= '9' &&
weight[1] == '0' && weight[2] == '0') {
_splash_window->set_font_weight(((int)weight[0] - 48) * 100);
} else {
nout << "parse_failure on font_weight " << weight << "\n";
}
}
_splash_window->set_wparams(_wparams);
_splash_window->set_install_label(_install_label);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
// Go get the required images.

View File

@ -111,6 +111,18 @@ get_root_dir() const {
return _root_dir;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_start_dir
// Access: Public
// Description: Returns the directory that the .p3d file should be
// mounted to and run from. This is usually the
// "start" subdirectory of the root_dir.
////////////////////////////////////////////////////////////////////
inline const string &P3DInstanceManager::
get_start_dir() const {
return _start_dir;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_platform
// Access: Public

View File

@ -201,7 +201,8 @@ initialize(int api_version, const string &contents_filename,
const string &platform, const string &log_directory,
const string &log_basename, bool trusted_environment,
bool console_environment,
const string &root_dir, const string &host_dir) {
const string &root_dir, const string &host_dir,
const string &start_dir) {
_api_version = api_version;
_host_url = host_url;
_verify_contents = verify_contents;
@ -258,14 +259,22 @@ initialize(int api_version, const string &contents_filename,
// TODO: Linux multiplatform support. Just add the
// appropriate platform strings to _supported_platforms.
} else {
nout << "Platform string was set by plugin to " << _platform << "\n";
}
if (_supported_platforms.empty()) {
// Hack for older plug-ins, which should still remain compatible with
// newer versions of the runtime distribution.
if (_platform == "win32") {
_supported_platforms.push_back("win_i386");
}
// We always support at least the specific platform on which we're
// running.
_supported_platforms.push_back(_platform);
}
#ifdef P3D_PLUGIN_LOG_DIRECTORY
if (_log_directory.empty()) {
_log_directory = P3D_PLUGIN_LOG_DIRECTORY;
@ -290,12 +299,18 @@ initialize(int api_version, const string &contents_filename,
} else {
_root_dir = root_dir;
}
_host_dir = host_dir;
if (start_dir.empty()) {
_start_dir = _root_dir + "/start";
} else {
_start_dir = start_dir;
}
// Allow the caller (e.g. panda3d.exe) to specify a log directory.
// Or, allow the developer to compile one in.
//
// Failing that, we write logfiles to Panda3D/log.
if (_log_directory.empty()) {
_log_directory = _root_dir + "/log";
@ -1507,8 +1522,10 @@ create_runtime_environment() {
// Make the certificate directory.
_certs_dir = _root_dir + "/certs";
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
if (!get_trusted_environment()) {
if (!mkdir_complete(_certs_dir, nout)) {
nout << "Couldn't mkdir " << _certs_dir << "\n";
}
}
_created_runtime_environment = true;

View File

@ -59,7 +59,8 @@ public:
bool trusted_environment,
bool console_environment,
const string &root_dir = "",
const string &host_dir = "");
const string &host_dir = "",
const string &start_dir = "");
inline bool is_initialized() const;
inline void reconsider_runtime_environment();
@ -69,6 +70,7 @@ public:
inline int get_api_version() const;
inline const string &get_host_url() const;
inline const string &get_root_dir() const;
inline const string &get_start_dir() const;
inline const string &get_platform() const;
inline const string &get_temp_directory() const;
inline const string &get_log_directory() const;
@ -173,6 +175,7 @@ private:
string _host_url;
string _root_dir;
string _host_dir;
string _start_dir;
string _certs_dir;
P3D_verify_contents _verify_contents;
string _platform;

View File

@ -36,6 +36,7 @@ P3DOsxSplashWindow::
P3DOsxSplashWindow(P3DInstance *inst, bool make_visible) :
P3DSplashWindow(inst, make_visible)
{
_font_attribs = NULL;
_install_progress = 0;
_progress_known = true;
_received_data = 0;
@ -59,6 +60,9 @@ P3DOsxSplashWindow::
DisposeWindow(_toplevel_window);
_toplevel_window = NULL;
}
if (_font_attribs != NULL) {
CFRelease(_font_attribs);
}
}
////////////////////////////////////////////////////////////////////
@ -123,6 +127,41 @@ set_wparams(const P3DWindowParams &wparams) {
}
}
}
// Determine the attributes of the font we're going to use.
int symbolic = 0;
if (_font_style != FS_normal) {
symbolic |= kCTFontItalicTrait;
}
if (_font_weight > 500) {
symbolic |= kCTFontBoldTrait;
}
CFNumberRef symbolic_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &symbolic);
CFStringRef traits_keys[1] = { kCTFontSymbolicTrait };
CFTypeRef traits_values[1] = { symbolic_ref };
CFDictionaryRef traits = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&traits_keys, (const void **)&traits_values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFStringRef family = CFStringCreateWithCString(NULL, _font_family.c_str(), kCFStringEncodingUTF8);
CFStringRef attribs_keys[2] = { kCTFontFamilyNameAttribute, kCTFontTraitsAttribute };
CFTypeRef attribs_values[2] = { family, traits };
CFDictionaryRef attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&attribs_keys, (const void **)&attribs_values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Create the font object.
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes(attribs);
CTFontRef font = CTFontCreateWithFontDescriptor(font_desc, _font_size, NULL);
CFStringRef keys[1] = { kCTFontAttributeName };
CFTypeRef values[1] = { font };
_font_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(font);
CFRelease(font_desc);
CFRelease(attribs);
CFRelease(traits);
CFRelease(family);
CFRelease(symbolic_ref);
}
////////////////////////////////////////////////////////////////////
@ -171,6 +210,9 @@ set_image_filename(const string &image_filename, ImagePlacement image_placement)
case IP_button_click:
load_image(_button_click_image, image_filename);
break;
default:
return;
}
refresh();
@ -333,10 +375,8 @@ paint_window_osx_cgcontext(CGContextRef context) {
CGColorRef bg = CGColorCreate(rgb_space, bg_components);
CGRect region = { { 0, 0 }, { _win_width, _win_height } };
CGContextBeginPath(context);
CGContextSetFillColorWithColor(context, bg);
CGContextAddRect(context, region);
CGContextFillPath(context);
CGContextFillRect(context, region);
CGColorRelease(bg);
CGColorSpaceRelease(rgb_space);
@ -445,8 +485,6 @@ handle_event_osx_event_record(const P3D_event_data &event) {
////////////////////////////////////////////////////////////////////
bool P3DOsxSplashWindow::
handle_event_osx_cocoa(const P3D_event_data &event) {
bool retval = false;
assert(event._event_type == P3D_ET_osx_cocoa);
const P3DCocoaEvent &ce = event._event._osx_cocoa._event;
@ -455,33 +493,31 @@ handle_event_osx_cocoa(const P3D_event_data &event) {
if (_visible) {
CGContextRef context = ce.data.draw.context;
paint_window_osx_cgcontext(context);
retval = true;
return true;
} else {
return false;
}
break;
case P3DCocoaEventMouseDown:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, true);
retval = true;
break;
return true;
case P3DCocoaEventMouseUp:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, false);
retval = true;
break;
return true;
case P3DCocoaEventMouseMoved:
case P3DCocoaEventMouseDragged:
set_mouse_data((int)ce.data.mouse.pluginX, (int)ce.data.mouse.pluginY, _mouse_down);
retval = true;
break;
return true;
case P3DCocoaEventFocusChanged:
_mouse_active = (ce.data.focus.hasFocus != 0);
retval = true;
break;
}
return true;
return retval;
default:
return false;
}
}
////////////////////////////////////////////////////////////////////
@ -612,42 +648,33 @@ paint_image(CGContextRef context, const OsxImageData &image) {
////////////////////////////////////////////////////////////////////
void P3DOsxSplashWindow::
paint_progress_bar(CGContextRef context) {
// Get some colors we'll need. We can't just use
// CGColorGetConstantColor(), since that requires 10.5.
CGFloat fg_components[] = { _fgcolor_r / 255.0f, _fgcolor_g / 255.0f, _fgcolor_b / 255.0f, 1 };
CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 };
CGFloat bar_components[] = { _barcolor_r / 255.0f, _barcolor_g / 255.0f, _barcolor_b / 255.0f, 1 };
CGFloat bar_bg_components[] = { _bar_bgcolor_r / 255.0f, _bar_bgcolor_g / 255.0f, _bar_bgcolor_b / 255.0f, 1 };
CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB();
CGColorRef fg = CGColorCreate(rgb_space, fg_components);
CGColorRef bg = CGColorCreate(rgb_space, bg_components);
CGColorRef bar = CGColorCreate(rgb_space, bar_components);
CGColorRef bar_bg = CGColorCreate(rgb_space, bar_bg_components);
// Get the proper placement for the progress bar.
int bar_x, bar_y, bar_width, bar_height;
get_bar_placement(bar_x, bar_y, bar_width, bar_height);
// We offset the bar by half a pixel, so we'll be drawing the
// one-pixel line through the middle of a pixel, and it won't try to
// antialias itself into a half-black two-pixel line.
float bar_xf = bar_x + 0.5;
float bar_yf = bar_y - 0.5;
CGRect bar_rect = { { bar_xf, bar_yf }, { bar_width, bar_height } };
CGRect bar_rect = { { bar_x, bar_y }, { bar_width, bar_height } };
// Clear the entire progress bar to white (or the background color).
CGContextBeginPath(context);
CGContextSetFillColorWithColor(context, bg);
CGContextAddRect(context, bar_rect);
CGContextFillPath(context);
CGContextSetFillColorWithColor(context, bar_bg);
CGContextFillRect(context, bar_rect);
// Draw the interior of the progress bar in blue (or the bar color).
if (_progress_known) {
int progress_width = (int)(bar_width * _install_progress + 0.5);
if (progress_width != 0) {
CGRect prog = { { bar_xf, bar_yf }, { progress_width, bar_height } };
CGContextBeginPath(context);
CGRect prog = { { bar_x, bar_y }, { progress_width, bar_height } };
CGContextSetFillColorWithColor(context, bar);
CGContextAddRect(context, prog);
CGContextFillPath(context);
CGContextFillRect(context, prog);
}
} else {
// Progress is unknown. Draw a moving block, not a progress bar
@ -660,57 +687,58 @@ paint_progress_bar(CGContextRef context) {
progress = block_travel * 2 - progress;
}
CGRect prog = { { bar_xf + progress, bar_yf }, { block_width, bar_height } };
CGContextBeginPath(context);
CGRect prog = { { bar_x + progress, bar_y }, { block_width, bar_height } };
CGContextSetFillColorWithColor(context, bar);
CGContextAddRect(context, prog);
CGContextFillPath(context);
CGContextFillRect(context, prog);
}
// Draw the black stroke around the progress bar.
CGContextBeginPath(context);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColorWithColor(context, fg);
CGContextAddRect(context, bar_rect);
CGContextStrokePath(context);
if (_bar_border > 0) {
// We offset the border by half a pixel, so we'll be drawing the
// one-pixel line through the middle of a pixel, and it won't try to
// antialias itself into a half-black two-pixel line.
CGRect border_rect = { { bar_x - 0.5, bar_y - 0.5 },
{ bar_width + 1, bar_height + 1 } };
CGContextBeginPath(context);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColorWithColor(context, fg);
for (int i = 0; i < _bar_border; ++i) {
CGContextAddRect(context, border_rect);
border_rect.origin.x -= 1;
border_rect.origin.y -= 1;
border_rect.size.width += 2;
border_rect.size.height += 2;
}
CGContextStrokePath(context);
}
if (!_install_label.empty()) {
// Now draw the install_label right above it.
// Need to invert the text so it won't be upside-down.
CGAffineTransform text_xform = CGAffineTransformMakeScale(1, -1);
CGContextSetTextMatrix(context, text_xform);
// Choose a suitable font.
float text_height = 15.0;
CGContextSelectFont(context, "Helvetica", text_height, kCGEncodingMacRoman);
// Now draw the install_label right above it.
CFStringRef string = CFStringCreateWithCString(NULL, _install_label.c_str(), kCFStringEncodingUTF8);
CFAttributedStringRef attr_string = CFAttributedStringCreate(NULL, string, _font_attribs);
CTLineRef line = CTLineCreateWithAttributedString(attr_string);
// Measure the text, for centering.
CGContextSetTextPosition(context, 0, 0);
CGContextSetTextDrawingMode(context, kCGTextInvisible);
CGContextShowText(context, _install_label.data(), _install_label.length());
CGPoint end_point = CGContextGetTextPosition(context);
float text_width = end_point.x;
int text_x = (int)(_win_width - text_width) / 2;
int text_y = (int)(bar_y - text_height * 1.5);
// Clear the rectangle behind the text to bg.
CGRect text_rect = { { text_x - 2, text_y - 2 }, { text_width + 4, text_height + 4 } };
CGContextBeginPath(context);
CGContextAddRect(context, text_rect);
CGContextSetFillColorWithColor(context, bg);
CGContextFillPath(context);
// Determine the placement based on the size of the text.
CGRect bounds = CTLineGetImageBounds(line, context);
float text_x = (_win_width - bounds.size.width) / 2.0f - bounds.origin.x;
float text_y = bar_y + bounds.origin.y - 4 - _bar_border;
// And finally, draw the text.
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, fg);
CGContextSetTextPosition(context, text_x, text_y);
CTLineDraw(line, context);
CGContextShowTextAtPoint(context, text_x, text_y + text_height,
_install_label.data(), _install_label.length());
CFRelease(line);
CFRelease(attr_string);
CFRelease(string);
}
CGColorRelease(bar_bg);
CGColorRelease(bar);
CGColorRelease(bg);
CGColorRelease(fg);

View File

@ -83,6 +83,8 @@ private:
OsxImageData _button_rollover_image;
OsxImageData _button_click_image;
CFDictionaryRef _font_attribs;
string _install_label;
double _install_progress;
bool _progress_known;

View File

@ -150,10 +150,10 @@ main(int argc, char *argv[]) {
}
}
if (!run_p3dpython(program_name, archive_file, input_handle, output_handle,
NULL, interactive_console)) {
int status = run_p3dpython(program_name, archive_file, input_handle,
output_handle, NULL, interactive_console);
if (status != 0) {
cerr << "Failure on startup.\n";
return 1;
}
return 0;
return status;
}

View File

@ -21,6 +21,11 @@
#include "py_panda.h"
extern "C" {
// This has been compiled-in by the build system, if all is well.
extern struct _frozen _PyImport_FrozenModules[];
};
// There is only one P3DPythonRun object in any given process space.
// Makes the statics easier to deal with, and we don't need multiple
// instances of this thing.
@ -54,16 +59,26 @@ P3DPythonRun(const char *program_name, const char *archive_file,
_interactive_console = interactive_console;
if (program_name != NULL) {
#if PY_MAJOR_VERSION >= 3
// Python 3 case: we have to convert it to a wstring.
TextEncoder enc;
enc.set_text(program_name);
_program_name = enc.get_wtext();
#else
// Python 2 is happy with a regular string.
_program_name = program_name;
#endif
}
if (archive_file != NULL) {
_archive_file = Filename::from_os_specific(archive_file);
}
_py_argc = 1;
_py_argv = (char **)malloc(2 * sizeof(char *));
#if PY_MAJOR_VERSION >= 3
_py_argv[0] = (wchar_t *)_program_name.c_str();
#else
_py_argv[0] = (char *)_program_name.c_str();
#endif
_py_argv[1] = NULL;
#ifdef NDEBUG
@ -75,13 +90,30 @@ P3DPythonRun(const char *program_name, const char *archive_file,
// Turn off the automatic load of site.py at startup.
extern int Py_NoSiteFlag;
Py_NoSiteFlag = 1;
Py_NoUserSiteDirectory = 1;
// Tell Python not to write bytecode files for loaded modules.
Py_DontWriteBytecodeFlag = 1;
// Prevent Python from complaining about finding the standard modules.
Py_FrozenFlag = 1;
// This contains the modules we need in order to call Py_Initialize,
// as well as the VFSImporter.
PyImport_FrozenModules = _PyImport_FrozenModules;
// Initialize Python. It appears to be important to do this before
// we open the pipe streams and spawn the thread, below.
#if PY_MAJOR_VERSION >= 3
Py_SetProgramName((wchar_t *)_program_name.c_str());
Py_SetPythonHome((wchar_t *)L"");
#else
Py_SetProgramName((char *)_program_name.c_str());
Py_SetPythonHome((char *)"");
#endif
Py_Initialize();
PyEval_InitThreads();
PySys_SetArgv(_py_argc, _py_argv);
PySys_SetArgvEx(_py_argc, _py_argv, 0);
// Open the error output before we do too much more.
if (log_pathname != NULL && *log_pathname != '\0') {
@ -137,8 +169,10 @@ P3DPythonRun::
// Access: Public
// Description: Runs the embedded Python process. This method does
// not return until the plugin is ready to exit.
//
// Returns the exit status, which will be 0 on success.
////////////////////////////////////////////////////////////////////
bool P3DPythonRun::
int P3DPythonRun::
run_python() {
#if defined(_WIN32) && defined(USE_DEBUG_PYTHON)
// On Windows, in a debug build, we have to preload sys.dll_suffix =
@ -154,36 +188,42 @@ run_python() {
// setting __path__ of frozen modules properly.
PyObject *panda3d_module = PyImport_AddModule("panda3d");
if (panda3d_module == NULL) {
nout << "Failed to create panda3d module:\n";
nout << "Failed to add panda3d module:\n";
PyErr_Print();
return false;
return 1;
}
// Set the __path__ such that it can find panda3d/core.pyd, etc.
// Set the __path__ such that it can find panda3d/_core.pyd, etc.
Filename panda3d_dir(dir, "panda3d");
string dir_str = panda3d_dir.to_os_specific();
PyObject *panda3d_dict = PyModule_GetDict(panda3d_module);
PyObject *panda3d_path = Py_BuildValue("[s#]", dir_str.data(), dir_str.length());
PyDict_SetItemString(panda3d_dict, "__path__", panda3d_path);
Py_DECREF(panda3d_path);
PyModule_AddObject(panda3d_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length()));
PyModule_AddStringConstant(panda3d_module, "__package__", "panda3d");
// Now we can load _vfsimporter.pyd. Since this is a magic frozen
// pyd, importing it automatically makes all of its frozen contents
// available to import as well.
PyObject *vfsimporter = PyImport_ImportModule("_vfsimporter");
if (vfsimporter == NULL) {
nout << "Failed to import _vfsimporter:\n";
PyErr_Print();
return false;
}
Py_DECREF(vfsimporter);
// And now we can import the VFSImporter module that was so defined.
PyObject *vfsimporter_module = PyImport_ImportModule("VFSImporter");
// Import the VFSImporter module that was frozen in.
PyObject *vfsimporter_module = PyImport_ImportModule("direct.showbase.VFSImporter");
if (vfsimporter_module == NULL) {
nout << "Failed to import VFSImporter:\n";
PyErr_Print();
return false;
return 1;
}
// Now repair the "direct" and "direct.showbase" trees, which were
// presumably frozen along with the VFSImporter, by setting their
// __path__ such that we can still find the other direct modules.
Filename direct_dir(dir, "direct");
PyObject *direct_module = PyImport_AddModule("direct");
if (direct_module != NULL) {
dir_str = direct_dir.to_os_specific();
PyModule_AddObject(direct_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length()));
PyModule_AddStringConstant(direct_module, "__package__", "direct");
}
PyObject *showbase_module = PyImport_AddModule("direct.showbase");
if (showbase_module != NULL) {
Filename showbase_dir(direct_dir, "showbase");
dir_str = showbase_dir.to_os_specific();
PyModule_AddObject(showbase_module, "__path__", Py_BuildValue("[s#]", dir_str.data(), dir_str.length()));
PyModule_AddStringConstant(showbase_module, "__package__", "direct.showbase");
}
// And register the VFSImporter.
@ -191,7 +231,7 @@ run_python() {
if (result == NULL) {
nout << "Failed to call VFSImporter.register():\n";
PyErr_Print();
return false;
return 1;
}
Py_DECREF(result);
Py_DECREF(vfsimporter_module);
@ -203,12 +243,12 @@ run_python() {
PT(Multifile) mf = new Multifile;
if (!mf->open_read(_archive_file)) {
nout << "Could not read " << _archive_file << "\n";
return false;
return 1;
}
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->mount(mf, dir, VirtualFileSystem::MF_read_only)) {
nout << "Could not mount " << _archive_file << "\n";
return false;
return 1;
}
// And finally, we can import the startup module.
@ -216,7 +256,7 @@ run_python() {
if (app_runner_module == NULL) {
nout << "Failed to import direct.p3d.AppRunner\n";
PyErr_Print();
return false;
return 1;
}
// Get the pointers to the objects needed within the module.
@ -224,7 +264,7 @@ run_python() {
if (app_runner_class == NULL) {
nout << "Failed to get AppRunner class\n";
PyErr_Print();
return false;
return 1;
}
// Construct an instance of AppRunner.
@ -232,47 +272,55 @@ run_python() {
if (_runner == NULL) {
nout << "Failed to construct AppRunner instance\n";
PyErr_Print();
return false;
return 1;
}
Py_DECREF(app_runner_class);
// Get the UndefinedObject class.
_undefined_object_class = PyObject_GetAttrString(app_runner_module, "UndefinedObject");
if (_undefined_object_class == NULL) {
// Import the JavaScript module.
PyObject *javascript_module = PyImport_ImportModule("direct.p3d.JavaScript");
if (javascript_module == NULL) {
nout << "Failed to import direct.p3d.JavaScript\n";
PyErr_Print();
return false;
}
// Get the UndefinedObject class.
_undefined_object_class = PyObject_GetAttrString(javascript_module, "UndefinedObject");
if (_undefined_object_class == NULL) {
PyErr_Print();
return 1;
}
// And the "Undefined" instance.
_undefined = PyObject_GetAttrString(app_runner_module, "Undefined");
_undefined = PyObject_GetAttrString(javascript_module, "Undefined");
if (_undefined == NULL) {
PyErr_Print();
return false;
return 1;
}
// Get the ConcreteStruct class.
_concrete_struct_class = PyObject_GetAttrString(app_runner_module, "ConcreteStruct");
_concrete_struct_class = PyObject_GetAttrString(javascript_module, "ConcreteStruct");
if (_concrete_struct_class == NULL) {
PyErr_Print();
return false;
return 1;
}
// Get the BrowserObject class.
_browser_object_class = PyObject_GetAttrString(app_runner_module, "BrowserObject");
_browser_object_class = PyObject_GetAttrString(javascript_module, "BrowserObject");
if (_browser_object_class == NULL) {
PyErr_Print();
return false;
return 1;
}
// Get the global TaskManager.
_taskMgr = PyObject_GetAttrString(app_runner_module, "taskMgr");
if (_taskMgr == NULL) {
PyErr_Print();
return false;
return 1;
}
Py_DECREF(app_runner_module);
Py_DECREF(javascript_module);
// Construct a Python wrapper around our methods we need to expose to Python.
static PyMethodDef p3dpython_methods[] = {
@ -282,15 +330,28 @@ run_python() {
"Send an asynchronous request to the plugin host" },
{ NULL, NULL, 0, NULL } /* Sentinel */
};
#if PY_MAJOR_VERSION >= 3
static PyModuleDef p3dpython_module = {
PyModuleDef_HEAD_INIT,
"p3dpython",
NULL,
-1,
p3dpython_methods,
NULL, NULL, NULL, NULL
};
PyObject *p3dpython = PyModule_Create(&p3dpython_module);
#else
PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
#endif
if (p3dpython == NULL) {
PyErr_Print();
return false;
return 1;
}
PyObject *request_func = PyObject_GetAttrString(p3dpython, "request_func");
if (request_func == NULL) {
PyErr_Print();
return false;
return 1;
}
// Now pass that func pointer back to our AppRunner instance, so it
@ -298,7 +359,7 @@ run_python() {
result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"N", request_func);
if (result == NULL) {
PyErr_Print();
return false;
return 1;
}
Py_DECREF(result);
@ -318,7 +379,7 @@ run_python() {
PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm");
if (check_comm == NULL) {
PyErr_Print();
return false;
return 1;
}
// Add it to the task manager. We do this instead of constructing a
@ -326,7 +387,7 @@ run_python() {
result = PyObject_CallMethod(_taskMgr, (char *)"add", (char *)"Ns", check_comm, "check_comm");
if (result == NULL) {
PyErr_Print();
return false;
return 1;
}
Py_DECREF(result);
@ -334,18 +395,48 @@ run_python() {
// taskMgr.run()).
PyObject *done = PyObject_CallMethod(_runner, (char *)"run", (char *)"");
if (done == NULL) {
int status = 1;
// An uncaught application exception, and not handled by
// appRunner.exceptionHandler.
PyErr_Print();
// appRunner.exceptionHandler. If it is a SystemExit, extract
// the exit status that we should return.
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
PyObject *ptype, *ptraceback;
PyObject *value = NULL;
PyErr_Fetch(&ptype, &value, &ptraceback);
if (value != NULL && PyExceptionInstance_Check(value)) {
PyObject *code = PyObject_GetAttrString(value, "code");
if (code) {
Py_DECREF(value);
value = code;
}
}
if (value == NULL || value == Py_None) {
status = 0;
#if PY_MAJOR_VERSION >= 3
} else if (PyLong_Check(value)) {
status = (int)PyLong_AsLong(value);
#else
} else if (PyInt_Check(value)) {
status = (int)PyInt_AsLong(value);
#endif
} else {
status = 1;
}
} else {
PyErr_Print();
}
if (_interactive_console) {
// Give an interactive user a chance to explore the exception.
run_interactive_console();
return true;
return 0;
}
// We're done.
return false;
return status;
}
// A normal exit from the taskManager. We're presumably done.
@ -355,7 +446,7 @@ run_python() {
run_interactive_console();
}
return true;
return 0;
}
////////////////////////////////////////////////////////////////////
@ -636,8 +727,11 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
result = PyBool_FromLong(PyObject_IsTrue(obj));
} else if (strcmp(method_name, "__int__") == 0) {
#if PY_MAJOR_VERSION >= 3
result = PyNumber_Long(obj);
#else
result = PyNumber_Int(obj);
#endif
} else if (strcmp(method_name, "__float__") == 0) {
result = PyNumber_Float(obj);
@ -1502,10 +1596,12 @@ pyobj_to_xml(PyObject *value) {
xvalue->SetAttribute("type", "bool");
xvalue->SetAttribute("value", PyObject_IsTrue(value));
#if PY_MAJOR_VERSION < 3
} else if (PyInt_Check(value)) {
// A plain integer value.
xvalue->SetAttribute("type", "int");
xvalue->SetAttribute("value", PyInt_AsLong(value));
#endif
} else if (PyLong_Check(value)) {
// A long integer value. This gets converted either as an integer
@ -1527,9 +1623,21 @@ pyobj_to_xml(PyObject *value) {
xvalue->SetAttribute("type", "float");
xvalue->SetDoubleAttribute("value", PyFloat_AsDouble(value));
} else if (PyUnicode_Check(value)) {
// A unicode value. Convert to utf-8 for the XML encoding.
xvalue->SetAttribute("type", "string");
#if PY_MAJOR_VERSION >= 3
// In Python 3, there are only unicode strings, and there is a
// handy function for getting the UTF-8 encoded version.
Py_ssize_t length = 0;
char *buffer = PyUnicode_AsUTF8AndSize(value, &length);
if (buffer != NULL) {
string str(buffer, length);
xvalue->SetAttribute("value", str);
}
#else
PyObject *as_str = PyUnicode_AsUTF8String(value);
if (as_str != NULL) {
char *buffer;
@ -1563,6 +1671,7 @@ pyobj_to_xml(PyObject *value) {
}
Py_DECREF(ustr);
}
#endif // PY_MAJOR_VERSION
} else if (PyTuple_Check(value)) {
// An immutable sequence. Pass it as a concrete.
@ -1601,7 +1710,11 @@ pyobj_to_xml(PyObject *value) {
PyObject *as_str;
if (PyUnicode_Check(a)) {
// The key is a unicode value.
#if PY_MAJOR_VERSION >= 3
as_str = a;
#else
as_str = PyUnicode_AsUTF8String(a);
#endif
} else {
// The key is a string value or something else. Make it
// a string.
@ -1609,7 +1722,12 @@ pyobj_to_xml(PyObject *value) {
}
char *buffer;
Py_ssize_t length;
#if PY_MAJOR_VERSION >= 3
buffer = PyUnicode_AsUTF8AndSize(as_str, &length);
if (buffer != NULL) {
#else
if (PyString_AsStringAndSize(as_str, &buffer, &length) != -1) {
#endif
string str(buffer, length);
xitem->SetAttribute("key", str);
}
@ -1694,7 +1812,11 @@ xml_to_pyobj(TiXmlElement *xvalue) {
} else if (strcmp(type, "int") == 0) {
int value;
if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(value);
#else
return PyInt_FromLong(value);
#endif
}
} else if (strcmp(type, "float") == 0) {

View File

@ -71,7 +71,7 @@ public:
const char *log_pathname, bool interactive_console);
~P3DPythonRun();
bool run_python();
int run_python();
void set_window_open(P3DCInstance *inst, bool is_open);
void request_keyboard_focus(P3DCInstance *inst);
@ -159,10 +159,15 @@ private:
int _session_id;
string _program_name;
Filename _archive_file;
int _py_argc;
char **_py_argv;
#if PY_MAJOR_VERSION >= 3
wchar_t *_py_argv[2];
wstring _program_name;
#else
char *_py_argv[2];
string _program_name;
#endif
bool _interactive_console;
PyObject *_runner;

View File

@ -100,6 +100,8 @@ void P3DSession::
shutdown() {
set_failed();
int exit_code = 0;
if (_p3dpython_started) {
// Tell the process we're going away.
TiXmlDocument doc;
@ -139,7 +141,14 @@ shutdown() {
nout << "Force-killing python process.\n";
TerminateProcess(_p3dpython_handle, 2);
}
DWORD dw_exit_code = 0;
if (!GetExitCodeProcess(_p3dpython_handle, &dw_exit_code)) {
nout << "GetExitCodeProcess failed, error: " << GetLastError() << "\n";
} else {
exit_code = (int)dw_exit_code;
}
CloseHandle(_p3dpython_handle);
_p3dpython_handle = INVALID_HANDLE_VALUE;
@ -179,18 +188,23 @@ shutdown() {
result = waitpid(_p3dpython_pid, &status, WNOHANG);
}
_p3dpython_pid = -1;
nout << "Python process has successfully stopped.\n";
if (WIFEXITED(status)) {
nout << " exited normally, status = "
<< WEXITSTATUS(status) << "\n";
exit_code = WEXITSTATUS(status);
nout << " exited normally, status = " << exit_code << "\n";
} else if (WIFSIGNALED(status)) {
nout << " signalled by " << WTERMSIG(status) << ", core = "
nout << " signalled by " << WTERMSIG(status) << ", core = "
<< WCOREDUMP(status) << "\n";
// This seems to be a popular shell convention.
exit_code = 128 + WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
nout << " stopped by " << WSTOPSIG(status) << "\n";
}
#endif // _WIN32
}
@ -211,6 +225,11 @@ shutdown() {
// Close the pipe now.
_pipe_read.close();
// If we had an exit status, pass it on to the runtime process.
if (exit_code != 0) {
_exit(exit_code);
}
}
////////////////////////////////////////////////////////////////////
@ -717,7 +736,7 @@ start_p3dpython(P3DInstance *inst) {
_keep_user_env = true;
}
if (!_keep_user_env) {
_start_dir = inst_mgr->get_root_dir() + "/start" + inst->get_start_dir_suffix();
_start_dir = inst_mgr->get_start_dir() + inst->get_start_dir_suffix();
mkdir_complete(_start_dir, nout);
}
replace_slashes(_start_dir);
@ -872,11 +891,13 @@ start_p3dpython(P3DInstance *inst) {
// These are the enviroment variables we forward from the current
// environment, if they are set.
const char *keep[] = {
"HOME", "USER",
"HOME", "USER",
#ifdef _WIN32
"SYSTEMROOT", "USERPROFILE", "COMSPEC",
"SYSTEMDRIVE", "ALLUSERSPROFILE", "APPDATA", "COMMONPROGRAMFILES",
"PROGRAMFILES", "WINDIR", "PROGRAMDATA", "USERDOMAIN",
#else
"LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG",
#endif
#ifdef HAVE_X11
"DISPLAY", "XAUTHORITY",
@ -928,7 +949,11 @@ start_p3dpython(P3DInstance *inst) {
const char *varc = var.c_str();
bool found = false;
for (int i = 0; dont_keep[i] != NULL && !found; ++i) {
#ifdef _WIN32
found = (_stricmp(dont_keep[i], varc) == 0);
#else
found = (strcmp(dont_keep[i], varc) == 0);
#endif
}
if (!found) {
// This variable is OK, keep it.
@ -1704,15 +1729,24 @@ posix_create_process() {
// its process. Report an error condition.
nout << "Python process stopped immediately.\n";
if (WIFEXITED(status)) {
nout << " exited normally, status = "
<< WEXITSTATUS(status) << "\n";
int code = WEXITSTATUS(status);
nout << " exited normally, status = " << code << "\n";
if (code != 0) {
_exit(code);
}
} else if (WIFSIGNALED(status)) {
nout << " signalled by " << WTERMSIG(status) << ", core = "
nout << " signalled by " << WTERMSIG(status) << ", core = "
<< WCOREDUMP(status) << "\n";
// This seems to be a popular shell convention.
_exit(128 + WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
nout << " stopped by " << WSTOPSIG(status) << "\n";
}
return -1;
}
#endif // _WIN32
@ -1794,10 +1828,12 @@ p3dpython_thread_run() {
return;
}
if (!run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(),
_input_handle, _output_handle, _log_pathname.c_str(),
_interactive_console)) {
int status = run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(),
_input_handle, _output_handle, _log_pathname.c_str(),
_interactive_console);
if (status != 0) {
nout << "Failure on startup.\n";
_exit(status);
}
}

View File

@ -48,6 +48,19 @@ P3DSplashWindow(P3DInstance *inst, bool make_visible) :
_barcolor_r = 0x6c;
_barcolor_g = 0xa5;
_barcolor_b = 0xe0;
_bar_bgcolor_r = _bgcolor_r;
_bar_bgcolor_g = _bgcolor_g;
_bar_bgcolor_b = _bgcolor_b;
_bar_border = 1;
_bar_bottom = 24;
_bar_width = 398;
_bar_height = 22;
_bar_width_ratio = 0.6;
_bar_height_ratio = 0.1;
_font_family = "Helvetica";
_font_size = 12;
_font_style = FS_normal;
_font_weight = FW_normal;
_button_width = 0;
_button_height = 0;
_button_x = 0;
@ -113,7 +126,7 @@ set_image_filename(const string &image_filename, ImagePlacement image_placement)
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_fgcolor
// Access: Public, Virtual
// Access: Public
// Description: Specifies the color that is used to display the text
// above the loading bar.
//
@ -129,7 +142,7 @@ set_fgcolor(int r, int g, int b) {
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bgcolor
// Access: Public, Virtual
// Access: Public
// Description: Specifies the solid color that is displayed behind
// the splash image, if any, or before the splash image
// is loaded.
@ -146,7 +159,7 @@ set_bgcolor(int r, int g, int b) {
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_barcolor
// Access: Public, Virtual
// Access: Public
// Description: Specifies the color that is used to fill the
// loading bar.
//
@ -160,6 +173,162 @@ set_barcolor(int r, int g, int b) {
_barcolor_b = b;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bar_bgcolor
// Access: Public
// Description: Specifies the solid color that is displayed behind
// the loading bar.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_bar_bgcolor(int r, int g, int b) {
nout << "bar_bgcolor " << r << ", " << g << ", " << b << "\n";
_bar_bgcolor_r = r;
_bar_bgcolor_g = g;
_bar_bgcolor_b = b;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bar_border
// Access: Public
// Description: Sets the width in pixels of the border around the
// loading bar, or 0 not to draw a bar at all.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_bar_border(int border) {
nout << "bar_border " << border << "\n";
_bar_border = border;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bar_bottom
// Access: Public
// Description: Sets the amount of background pixels between the
// bottom edge of the window and the bottom edge of
// the loading bar border.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_bar_bottom(int bottom) {
nout << "bar_bottom " << bottom << "\n";
_bar_bottom = bottom;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bar_width
// Access: Public
// Description: Sets the width of the loading bar. If percent is
// true, it is interpreted as a percentage of the
// window width. If false, it is interpreted as an
// absolute width in pixels.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_bar_width(int width, bool percent) {
nout << "bar_width " << width;
if (percent) {
nout << '%';
}
nout << '\n';
if (percent) {
_bar_width = -1;
_bar_width_ratio = abs(width) / 100.0;
} else {
_bar_width = abs(width);
_bar_width_ratio = 1.0;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_bar_height
// Access: Public
// Description: Sets the height of the loading bar. If percent is
// true, it is interpreted as a percentage of the
// window height. If false, it is interpreted as an
// absolute height in pixels.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_bar_height(int height, bool percent) {
nout << "bar_height " << height;
if (percent) {
nout << '%';
}
nout << '\n';
if (percent) {
_bar_height = -1;
_bar_height_ratio = abs(height) / 100.0;
} else {
_bar_height = abs(height);
_bar_height_ratio = 1.0;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_font_family
// Access: Public
// Description: Sets the font family of the text above the loading
// bar.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_font_family(const string &family) {
nout << "font_family " << family << "\n";
_font_family = family;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_font_size
// Access: Public
// Description: Sets the font size in pixels of the text above the
// loading bar. The default value is 12.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_font_size(int size) {
nout << "font_size " << size << "\n";
_font_size = size;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_font_style
// Access: Public
// Description: Sets the font style of the text above the loading
// bar.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_font_style(FontStyle style) {
nout << "font_style " << style << "\n";
_font_style = style;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_font_weight
// Access: Public
// Description: Sets the font weight of the text above the loading
// bar. The default is FW_normal. It should be
// a multiple of 100 in the range 100-900.
//
// This may only be set before wparams is set.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_font_weight(int weight) {
nout << "font_weight " << weight << "\n";
_font_weight = weight;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_install_label
// Access: Public, Virtual
@ -271,10 +440,21 @@ read_image_data(ImageData &image, string &data,
void P3DSplashWindow::
get_bar_placement(int &bar_x, int &bar_y,
int &bar_width, int &bar_height) {
bar_width = min((int)(_win_width * 0.6), 400);
bar_height = min((int)(_win_height * 0.1), 24);
bar_width = (int)(_win_width * _bar_width_ratio);
bar_height = (int)(_win_height * _bar_height_ratio);
if (_bar_width >= 0) {
bar_width = min(bar_width, _bar_width);
}
if (_bar_height >= 0) {
bar_height = min(bar_height, _bar_height);
}
// Horizontally center the bar, and set it at a fixed distance
// from the bottom edge of the splash window.
bar_x = (_win_width - bar_width) / 2;
bar_y = (_win_height - bar_height * 2);
bar_y = _win_height - _bar_bottom - _bar_border - bar_height;
}
////////////////////////////////////////////////////////////////////

View File

@ -51,12 +51,32 @@ public:
IP_button_click,
IP_none
};
enum FontStyle {
FS_normal,
FS_italic,
FS_oblique
};
enum FontWeight {
FW_normal = 400,
FW_medium = 500,
FW_bold = 700,
FW_black = 900
};
virtual void set_image_filename(const string &image_filename,
ImagePlacement image_placement);
virtual void set_fgcolor(int r, int g, int b);
virtual void set_bgcolor(int r, int g, int b);
virtual void set_barcolor(int r, int g, int b);
void set_fgcolor(int r, int g, int b);
void set_bgcolor(int r, int g, int b);
void set_barcolor(int r, int g, int b);
void set_bar_bgcolor(int r, int g, int b);
void set_bar_border(int border);
void set_bar_bottom(int bottom);
void set_bar_width(int width, bool percent=false);
void set_bar_height(int height, bool percent=false);
void set_font_family(const string &family);
void set_font_size(int size);
void set_font_style(FontStyle style);
void set_font_weight(int weight);
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress,
bool is_progress_known, size_t received_data);
@ -105,6 +125,19 @@ protected:
int _fgcolor_r, _fgcolor_g, _fgcolor_b;
int _bgcolor_r, _bgcolor_g, _bgcolor_b;
int _barcolor_r, _barcolor_g, _barcolor_b;
int _bar_bgcolor_r, _bar_bgcolor_g, _bar_bgcolor_b;
int _bar_border;
private:
int _bar_bottom;
int _bar_width, _bar_height;
double _bar_width_ratio, _bar_height_ratio;
protected:
string _font_family;
int _font_size;
FontStyle _font_style;
int _font_weight;
// The region of the window for accepting button clicks.
int _button_width, _button_height;

View File

@ -34,9 +34,11 @@ P3DWinSplashWindow(P3DInstance *inst, bool make_visible) :
_thread = NULL;
_thread_id = 0;
_hwnd = NULL;
_font = NULL;
_fg_brush = NULL;
_bg_brush = NULL;
_bar_brush = NULL;
_bar_bg_brush = NULL;
_thread_running = false;
_install_progress = 0.0;
_progress_known = true;
@ -497,9 +499,21 @@ make_window() {
ShowWindow(_hwnd, SW_HIDE);
}
// Load the requested font.
_font = CreateFontA(-_font_size, 0, 0, 0, _font_weight,
(_font_style != FS_normal), FALSE, FALSE,
ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, VARIABLE_PITCH, _font_family.c_str());
if (_font == NULL) {
nout << "CreateFont failed: " << GetLastError() << "\n";
_font = (HFONT)GetStockObject(ANSI_VAR_FONT);
}
_fg_brush = CreateSolidBrush(RGB(_fgcolor_r, _fgcolor_g, _fgcolor_b));
_bg_brush = CreateSolidBrush(RGB(_bgcolor_r, _bgcolor_g, _bgcolor_b));
_bar_brush = CreateSolidBrush(RGB(_barcolor_r, _barcolor_g, _barcolor_b));
_bar_bg_brush = CreateSolidBrush(RGB(_bar_bgcolor_r, _bar_bgcolor_g, _bar_bgcolor_b));
}
////////////////////////////////////////////////////////////////////
@ -635,6 +649,10 @@ close_window() {
DeleteObject(_bar_brush);
_bar_brush = NULL;
}
if (_bar_bg_brush != NULL) {
DeleteObject(_bar_bg_brush);
_bar_bg_brush = NULL;
}
_background_image.dump_image();
_button_ready_image.dump_image();
@ -794,7 +812,7 @@ paint_progress_bar(HDC dc) {
RECT bar_rect = { bar_x, bar_y, bar_x + bar_width, bar_y + bar_height };
// Clear the entire progress bar to white (or the background color).
FillRect(dc, &bar_rect, _bg_brush);
FillRect(dc, &bar_rect, _bar_bg_brush);
// Draw the interior of the progress bar in blue (or the bar color).
if (_drawn_progress_known) {
@ -820,23 +838,31 @@ paint_progress_bar(HDC dc) {
}
// Now draw a black (or foreground) border around the progress bar.
FrameRect(dc, &bar_rect, _fg_brush);
if (_bar_border >= 0) {
RECT border_rect = bar_rect;
for (int i = 0; i < _bar_border; ++i) {
--border_rect.left;
--border_rect.top;
++border_rect.right;
++border_rect.bottom;
FrameRect(dc, &border_rect, _fg_brush);
}
}
if (!_drawn_label.empty()) {
// Now draw the install_label right above it.
const char *text = _drawn_label.c_str();
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
// Measure the text, for centering.
SelectObject(dc, font);
SelectObject(dc, _font);
SIZE text_size;
GetTextExtentPoint32(dc, text, strlen(text), &text_size);
int text_width = text_size.cx;
int text_height = text_size.cy;
int text_x = (_win_width - text_width) / 2;
int text_y = bar_y - (int)(text_height * 1.5);
int text_y = bar_y - (int)(text_height * 1.5) - _bar_border;
// Clear the rectangle behind the text to white.
RECT text_rect = { text_x - 2, text_y - 2, text_x + text_width + 4, text_y + text_height + 4 };
@ -856,7 +882,7 @@ paint_progress_bar(HDC dc) {
// Access: Private
// Description: The windows event-processing handler.
////////////////////////////////////////////////////////////////////
LONG P3DWinSplashWindow::
LRESULT P3DWinSplashWindow::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_DESTROY:
@ -937,7 +963,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
// Access: Private, Static
// Description: The windows event-processing handler, static version.
////////////////////////////////////////////////////////////////////
LONG P3DWinSplashWindow::
LRESULT P3DWinSplashWindow::
st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
LONG_PTR self = GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (self == NULL) {

View File

@ -68,8 +68,8 @@ private:
void paint_window(HDC dc);
bool paint_image(HDC dc, const WinImageData &image, bool use_alpha);
void paint_progress_bar(HDC dc);
LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
LRESULT window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static LRESULT WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
class WinImageData : public ImageData {
@ -109,9 +109,11 @@ private:
HANDLE _thread;
DWORD _thread_id;
HWND _hwnd;
HFONT _font;
HBRUSH _fg_brush;
HBRUSH _bg_brush;
HBRUSH _bar_brush;
HBRUSH _bar_bg_brush;
static bool _registered_window_class;
};

View File

@ -47,11 +47,14 @@ P3DX11SplashWindow(P3DInstance *inst, bool make_visible) :
_display = None;
_window = None;
_screen = 0;
_font = NULL;
_graphics_context = None;
_bar_context = None;
_bar_bg_context = None;
_fg_pixel = -1;
_bg_pixel = -1;
_bar_pixel = -1;
_bar_bg_pixel = -1;
_own_display = false;
_install_progress = 0.0;
_progress_known = true;
@ -609,10 +612,15 @@ subprocess_run() {
get_bar_placement(bar_x, bar_y, bar_width, bar_height);
if (needs_draw_label) {
int text_width = _install_label.size() * 6;
int text_height = 10;
int direction, ascent, descent;
XCharStruct extents;
XTextExtents(_font, _install_label.c_str(), _install_label.size(),
&direction, &ascent, &descent, &extents);
int text_width = extents.width;
int text_height = extents.ascent + extents.descent;
int text_x = (_win_width - text_width) / 2;
int text_y = bar_y - 4;
int text_y = bar_y - descent - _bar_border - 4;
XClearArea(_display, _window,
text_x - 2, text_y - text_height - 2,
@ -624,25 +632,44 @@ subprocess_run() {
}
if (needs_redraw_progress) {
XClearArea(_display, _window,
bar_x, bar_y, bar_width, bar_height, false);
XDrawRectangle(_display, _window, _graphics_context,
bar_x, bar_y, bar_width, bar_height);
// Draw the bar background.
if (_bar_bg_context != None) {
XFillRectangle(_display, _window, _bar_bg_context,
bar_x, bar_y, bar_width, bar_height);
} else {
XClearArea(_display, _window,
bar_x, bar_y, bar_width, bar_height, false);
}
// Draw the border around the bar.
int border_x = bar_x - 1;
int border_y = bar_y - 1;
int border_width = bar_width + 1;
int border_height = bar_height + 1;
for (int i = 0; i < _bar_border; ++i) {
XDrawRectangle(_display, _window, _graphics_context,
border_x, border_y, border_width, border_height);
border_x -= 1;
border_y -= 1;
border_width += 2;
border_height += 2;
}
needs_update_progress = true;
needs_redraw_progress = false;
}
if (needs_update_progress) {
if (_progress_known) {
int progress_width = (int)((bar_width - 2) * _install_progress + 0.5);
int progress_width = (int)((bar_width - 1) * _install_progress + 0.5);
XFillRectangle(_display, _window, _bar_context,
bar_x + 1, bar_y + 1,
progress_width + 1, bar_height - 1);
bar_x, bar_y,
progress_width + 1, bar_height);
} else {
// Progress is unknown. Draw a moving block, not a progress bar
// filling up.
int block_width = (int)(bar_width * 0.1 + 0.5);
int block_travel = (bar_width - 2) - block_width;
int block_travel = (bar_width - 1) - block_width;
int progress = (int)(_received_data * _unknown_progress_rate);
progress = progress % (block_travel * 2);
if (progress > block_travel) {
@ -650,8 +677,8 @@ subprocess_run() {
}
XFillRectangle(_display, _window, _bar_context,
bar_x + 1 + progress, bar_y + 1,
block_width + 1, bar_height - 1);
bar_x + progress, bar_y,
block_width + 1, bar_height);
}
needs_update_progress = false;
}
@ -681,10 +708,13 @@ subprocess_run() {
}
}
if (input_ready) {
while (input_ready) {
// Empty the pipe of whatever is in it.
receive_command();
input_ready = _pipe_read.has_gdata();
}
// Sleep a good amount in order not to lock up the system.
struct timespec req;
req.tv_sec = 0;
req.tv_nsec = 50000000; // 50 ms
@ -955,10 +985,82 @@ setup_gc() {
return;
}
XFontStruct* fs = XLoadQueryFont(_display, "6x13");
char style = 'r';
if (_font_style == FS_oblique) {
style = 'o';
} else if (_font_style == FS_italic) {
style = 'i';
}
// Determine the order at which to try the various weights. From:
// https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
const char *const *try_weights;
const int num_weights = 7;
if (_font_weight > 700) {
static const char *const weights[] = {"black", "bold", "demibold", "semibold", "medium", "regular", "extralight"};
try_weights = weights;
} else if (_font_weight > 600) {
static const char *const weights[] = {"bold", "black", "demibold", "semibold", "medium", "regular", "extralight"};
try_weights = weights;
} else if (_font_weight > 500) {
static const char *const weights[] = {"demibold", "semibold", "bold", "black", "medium", "regular", "extralight"};
try_weights = weights;
} else if (_font_weight == 500) {
static const char *const weights[] = {"medium", "regular", "extralight", "demibold", "semibold", "bold", "black"};
try_weights = weights;
} else if (_font_weight >= 400) {
static const char *const weights[] = {"regular", "medium", "extralight", "demibold", "semibold", "bold", "black"};
try_weights = weights;
} else {
static const char *const weights[] = {"extralight", "regular", "medium", "demibold", "semibold", "bold", "black"};
try_weights = weights;
}
char font_name[1024];
// Go through the weights array to find the best matching font.
for (int i = 0; i < num_weights; ++i) {
const char *weight_name = try_weights[i];
// Compose the proper pattern for finding the desired font face.
snprintf(font_name, 1024, "-*-%s-%s-%c-normal--%d-*-*-*-*-*-iso8859-1",
_font_family.c_str(), weight_name, style, _font_size);
_font = XLoadQueryFont(_display, font_name);
if (_font != NULL) {
break;
}
nout << "Font " << font_name << " unavailable.\n";
if (style == 'i' || style == 'o') {
// If oblique is not found, try italic, and vice versa.
char style2 = 216 - style;
snprintf(font_name, 1024, "-*-%s-%s-%c-normal--%d-*-*-*-*-*-iso8859-1",
_font_family.c_str(), weight_name, style2, _font_size);
_font = XLoadQueryFont(_display, font_name);
if (_font != NULL) {
break;
}
nout << "Font " << font_name << " unavailable.\n";
}
}
if (_font != NULL) {
nout << "Loaded font " << font_name << "\n";
} else {
nout << "Using fallback font 6x13.\n";
_font = XLoadQueryFont(_display, "6x13");
}
XGCValues gcval;
gcval.font = fs->fid;
gcval.font = _font->fid;
gcval.function = GXcopy;
gcval.plane_mask = AllPlanes;
gcval.foreground = BlackPixel(_display, _screen);
@ -988,6 +1090,24 @@ setup_gc() {
_bar_context = XCreateGC(_display, _window,
GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval);
// And another for the background color of the bar.
if (_bar_bgcolor_r != _bgcolor_r || _bar_bgcolor_g != _bgcolor_g ||
_bar_bgcolor_b != _bgcolor_b) {
XColor bar_bg;
bar_bg.red = _bar_bgcolor_r * 0x101;
bar_bg.green = _bar_bgcolor_g * 0x101;
bar_bg.blue = _bar_bgcolor_b * 0x101;
bar_bg.flags = DoRed | DoGreen | DoBlue;
if (XAllocColor(_display, colormap, &bar_bg)) {
_bar_bg_pixel = bar_bg.pixel;
gcval.foreground = bar_bg.pixel;
}
_bar_bg_context = XCreateGC(_display, _window,
GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval);
}
}
////////////////////////////////////////////////////////////////////
@ -1013,6 +1133,17 @@ close_window() {
XFreeColors(_display, colormap, &_bar_pixel, 1, 0);
}
if (_bar_bg_context != None) {
if (_bar_bg_context != _graphics_context) {
XFreeGC(_display, _bar_bg_context);
}
_bar_bg_context = None;
// Also free the color we allocated.
Colormap colormap = DefaultColormap(_display, _screen);
XFreeColors(_display, colormap, &_bar_bg_pixel, 1, 0);
}
if (_fg_pixel != -1) {
Colormap colormap = DefaultColormap(_display, _screen);
XFreeColors(_display, colormap, &_fg_pixel, 1, 0);

View File

@ -86,7 +86,7 @@ private:
void setup_gc();
void close_window();
void update_image(X11ImageData &image);
void update_image(X11ImageData &image);
void compose_image();
bool scale_image(vector<unsigned char> &image0, int &image0_width, int &image0_height,
X11ImageData &image);
@ -123,17 +123,20 @@ private:
double _install_progress;
bool _progress_known;
size_t _received_data;
string _label_text;
X11_Display *_display;
int _screen;
XFontStruct *_font;
GC _graphics_context;
GC _bar_context;
GC _bar_bg_context;
unsigned long _fg_pixel;
unsigned long _bg_pixel;
unsigned long _bar_pixel;
unsigned long _bar_bg_pixel;
X11_Window _window;
};

View File

@ -39,7 +39,8 @@ P3D_initialize(int api_version, const char *contents_filename,
const char *platform, const char *log_directory,
const char *log_basename, bool trusted_environment,
bool console_environment,
const char *root_dir, const char *host_dir) {
const char *root_dir, const char *host_dir,
const char *start_dir) {
if (api_version < 10 || api_version > P3D_API_VERSION) {
// Can't accept an incompatible version.
return false;
@ -89,12 +90,16 @@ P3D_initialize(int api_version, const char *contents_filename,
host_dir = "";
}
if (api_version < 17 || start_dir == NULL) {
start_dir = "";
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
bool result = inst_mgr->initialize(api_version, contents_filename, host_url,
verify_contents, platform,
log_directory, log_basename,
trusted_environment, console_environment,
root_dir, host_dir);
root_dir, host_dir, start_dir);
RELEASE_LOCK(_api_lock);
return result;
}

View File

@ -53,7 +53,11 @@
#endif
#else /* _WIN32 */
#if defined(BUILDING_P3D_PLUGIN) && defined(__GNUC__)
#define EXPCL_P3D_PLUGIN __attribute__((visibility("default")))
#else
#define EXPCL_P3D_PLUGIN
#endif
#endif /* _WIN32 */
@ -79,7 +83,7 @@ extern "C" {
(below). This number will be incremented whenever there are changes
to any of the interface specifications defined in this header
file. */
#define P3D_API_VERSION 16
#define P3D_API_VERSION 17
/************************ GLOBAL FUNCTIONS **************************/
@ -161,7 +165,8 @@ P3D_initialize_func(int api_version, const char *contents_filename,
const char *platform,
const char *log_directory, const char *log_basename,
bool trusted_environment, bool console_environment,
const char *root_dir, const char *host_dir);
const char *root_dir, const char *host_dir,
const char *start_dir);
/* This function should be called to unload the core API. It will
release all internally-allocated memory and return the core API to

View File

@ -19,16 +19,17 @@
// Function: run_p3dpython
// Description: This externally-visible function is the main entry
// point to this DLL, and it starts the whole thing
// running. Returns true on success, false on failure.
// running. Returns the exit status, which will be
// 0 on success, 1 or otherwise on failure.
////////////////////////////////////////////////////////////////////
bool
int
run_p3dpython(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle input_handle, FHandle output_handle,
const char *log_pathname, bool interactive_console) {
P3DPythonRun::_global_ptr =
new P3DPythonRun(program_name, archive_file, input_handle, output_handle,
P3DPythonRun::_global_ptr =
new P3DPythonRun(program_name, archive_file, input_handle, output_handle,
log_pathname, interactive_console);
bool result = P3DPythonRun::_global_ptr->run_python();
int result = P3DPythonRun::_global_ptr->run_python();
delete P3DPythonRun::_global_ptr;
P3DPythonRun::_global_ptr = NULL;
return result;

View File

@ -26,14 +26,14 @@
#define EXPCL_P3DPYTHON
#endif
typedef bool
typedef int
run_p3dpython_func(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle input_handle, FHandle output_handle,
const char *log_pathname, bool interactive_console);
extern "C" EXPCL_P3DPYTHON bool
extern "C" EXPCL_P3DPYTHON int
run_p3dpython(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle input_handle, FHandle output_handle,
const char *log_pathname, bool interactive_console);
#endif

View File

@ -581,12 +581,12 @@ int PPInstance::LoadPlugin( const std::string& dllFilename )
pathname = override_filename;
}
#endif // P3D_PLUGIN_P3D_PLUGIN
nout << "Attempting to load core API from " << pathname << "\n";
string contents_filename = m_rootDir + "/contents.xml";
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
P3D_VC_normal, "", "", "", false, false,
m_rootDir, "", nout)) {
P3D_VC_normal, "", "", "", false, false,
m_rootDir, "", "", nout)) {
nout << "Unable to launch core API in " << pathname << "\n";
error = 1;
} else {

View File

@ -1738,8 +1738,8 @@ do_load_plugin() {
nout << "Attempting to load core API from " << pathname << "\n";
string contents_filename = _root_dir + "/contents.xml";
if (!load_plugin(pathname, contents_filename, PANDA_PACKAGE_HOST_URL,
P3D_VC_normal, "", "", "", false, false,
_root_dir, "", nout)) {
P3D_VC_normal, "", "", "", false, false,
_root_dir, "", "", nout)) {
nout << "Unable to launch core API in " << pathname << "\n";
set_failed();
return;

View File

@ -53,7 +53,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
// the + 1 from the test.
_read_offset_check = read_offset + (streampos)1;
if (_read_offset_check == (streampos)0xFF3D3D01) {
cerr << "This program is not intended to be run directly.\nIt is used by pdeploy to construct an embedded Panda3D application.\n";
cerr << "This program is not intended to be run directly.\nIt is used "
"by pdeploy to construct an embedded Panda3D application.\n";
return 1;
}
@ -86,22 +87,30 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
string value;
string root_dir;
string host_dir;
string start_dir;
while (true) {
if (curchr == EOF) {
cerr << "Truncated stream\n";
return(1);
return 1;
} else if (curchr == 0) {
// Two null bytes in a row means we've reached the end of the data.
if (havenull) {
break;
}
// This means we haven't seen an '=' character yet.
if (keyword == "") {
if (curstr != "") {
cerr << "Ignoring token '" << curstr << "' without value\n";
}
} else if (keyword == "start_dir") {
// Don't pass this on as a token, since it has slightly different
// semantics when used as an HTML token.
start_dir = curstr;
} else {
value.assign(curstr);
P3D_token token;
@ -118,6 +127,8 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
_got_win_size = true;
} else if (keyword == "log_basename") {
_log_basename = value;
} else if (keyword == "log_directory") {
_log_dirname = value;
} else if (keyword == "root_dir") {
root_dir = value;
} else if (keyword == "host_dir") {
@ -168,6 +179,13 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
_host_dir = host_dir_f.to_os_specific();
}
// Make the start directory absolute
if (!start_dir.empty()) {
Filename start_dir_f(start_dir);
start_dir_f.make_absolute(f.get_dirname());
_start_dir = start_dir_f.to_os_specific();
}
// Initialize the core API by directly assigning all of the function
// pointers.
P3D_initialize_ptr = &P3D_initialize;
@ -229,18 +247,17 @@ run_embedded(streampos read_offset, int argc, char *argv[]) {
// function pointers. This will also call P3D_initialize().
if (!init_plugin("", _host_url, _verify_contents, _this_platform,
_log_dirname, _log_basename, true, _console_environment,
_root_dir, _host_dir, cerr)) {
_root_dir, _host_dir, _start_dir, cerr)) {
cerr << "Unable to launch core API\n";
return 1;
}
// Create a plugin instance and run the program
P3D_instance *inst = create_instance(f, true, argv, argc, read_offset);
_instances.insert(inst);
run_main_loop();
unload_plugin(cerr);
return 0;
}

View File

@ -356,6 +356,7 @@ bool Panda3D::
get_plugin() {
// First, look for the existing contents.xml file.
bool success = false;
bool is_fresh = false;
Filename contents_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
if (_verify_contents != P3D_VC_force) {
@ -370,75 +371,100 @@ get_plugin() {
if (!success) {
// Couldn't read it (or it wasn't current enough), so go get a new
// one.
HTTPClient *http = HTTPClient::get_global_ptr();
// Try the super_mirror first.
if (!_super_mirror_url_prefix.empty()) {
// We don't bother putting a uniquifying query string when we're
// downloading this file from the super_mirror. The super_mirror
// is by definition a cache, so it doesn't make sense to bust
// caches here.
string url = _super_mirror_url_prefix + "contents.xml";
PT(HTTPChannel) channel = http->make_channel(false);
channel->get_document(url);
Filename tempfile = Filename::temporary("", "p3d_");
if (!channel->download_to_file(tempfile)) {
cerr << "Unable to download " << url << "\n";
tempfile.unlink();
} else {
// Successfully downloaded from the super_mirror; try to read it.
success = read_contents_file(tempfile, true);
tempfile.unlink();
}
if (!download_contents_file(contents_filename)) {
// We don't have a usable contents.xml file.
return false;
}
is_fresh = true;
}
if (!success) {
// Go download contents.xml from the actual host.
ostringstream strm;
strm << _host_url_prefix << "contents.xml";
// Append a uniquifying query string to the URL to force the
// download to go all the way through any caches. We use the time
// in seconds; that's unique enough.
strm << "?" << time(NULL);
string url = strm.str();
// We might as well explicitly request the cache to be disabled too,
// since we have an interface for that via HTTPChannel.
DocumentSpec request(url);
request.set_cache_control(DocumentSpec::CC_no_cache);
PT(HTTPChannel) channel = http->make_channel(false);
channel->get_document(request);
// Since we have to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
// First, download it to a temporary file.
Filename tempfile = Filename::temporary("", "p3d_");
if (!channel->download_to_file(tempfile)) {
cerr << "Unable to download " << url << "\n";
// Couldn't download, but try to read the existing contents.xml
// file anyway. Maybe it's good enough.
success = read_contents_file(contents_filename, false);
} else {
// Successfully downloaded; read it and move it into place.
success = read_contents_file(tempfile, true);
}
// Now that we've downloaded the contents file successfully, start
// the Core API.
if (!get_core_api()) {
// We failed. Make sure contents.xml is up-to-date and try again.
if (!is_fresh && download_contents_file(contents_filename) && get_core_api()) {
return true;
} else {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::download_contents_file
// Access: Protected
// Description: Redownloads the contents.xml file from the named
// URL without first checking if it is up to date.
// Returns true if we have a contents.xml file that
// might be usable, false otherwise.
////////////////////////////////////////////////////////////////////
bool Panda3D::
download_contents_file(const Filename &contents_filename) {
bool success = false;
HTTPClient *http = HTTPClient::get_global_ptr();
// Try the super_mirror first.
if (!_super_mirror_url_prefix.empty()) {
// We don't bother putting a uniquifying query string when we're
// downloading this file from the super_mirror. The super_mirror
// is by definition a cache, so it doesn't make sense to bust
// caches here.
string url = _super_mirror_url_prefix + "contents.xml";
PT(HTTPChannel) channel = http->make_channel(false);
channel->get_document(url);
Filename tempfile = Filename::temporary("", "p3d_");
if (!channel->download_to_file(tempfile)) {
cerr << "Unable to download " << url << "\n";
tempfile.unlink();
} else {
// Successfully downloaded from the super_mirror; try to read it.
success = read_contents_file(tempfile, true);
tempfile.unlink();
}
}
if (success) {
// Now that we've downloaded the contents file successfully, start
// the Core API.
success = get_core_api();
if (!success) {
// Go download contents.xml from the actual host.
ostringstream strm;
strm << _host_url_prefix << "contents.xml";
// Append a uniquifying query string to the URL to force the
// download to go all the way through any caches. We use the time
// in seconds; that's unique enough.
strm << "?" << time(NULL);
string url = strm.str();
// We might as well explicitly request the cache to be disabled too,
// since we have an interface for that via HTTPChannel.
DocumentSpec request(url);
request.set_cache_control(DocumentSpec::CC_no_cache);
PT(HTTPChannel) channel = http->make_channel(false);
channel->get_document(request);
// Since we have to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
// First, download it to a temporary file.
Filename tempfile = Filename::temporary("", "p3d_");
if (!channel->download_to_file(tempfile)) {
cerr << "Unable to download " << url << "\n";
// Couldn't download, but try to read the existing contents.xml
// file anyway. Maybe it's good enough.
success = read_contents_file(contents_filename, false);
} else {
// Successfully downloaded; read it and move it into place.
success = read_contents_file(tempfile, true);
}
tempfile.unlink();
}
return success;
@ -690,7 +716,6 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
}
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::get_core_api
// Access: Protected
@ -700,78 +725,12 @@ choose_random_mirrors(vector_string &result, int num_mirrors) {
////////////////////////////////////////////////////////////////////
bool Panda3D::
get_core_api() {
bool is_fresh = false;
if (!_coreapi_dll.quick_verify(_root_dir)) {
// The DLL file needs to be downloaded. Build up our list of
// URL's to attempt to download it from, in reverse order.
string url;
vector_string core_urls;
// Our last act of desperation: hit the original host, with a
// query uniquifier, to break through any caches.
ostringstream strm;
strm << _download_url_prefix << _coreapi_dll.get_filename()
<< "?" << time(NULL);
url = strm.str();
core_urls.push_back(url);
// Before we try that, we'll hit the original host, without a
// uniquifier.
url = _download_url_prefix;
url += _coreapi_dll.get_filename();
core_urls.push_back(url);
// And before we try that, we'll try two mirrors, at random.
vector_string mirrors;
choose_random_mirrors(mirrors, 2);
for (vector_string::iterator si = mirrors.begin();
si != mirrors.end();
++si) {
url = (*si) + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// The very first thing we'll try is the super_mirror, if we have
// one.
if (!_super_mirror_url_prefix.empty()) {
url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// Now pick URL's off the list, and try them, until we have
// success.
Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
pathname.make_dir();
HTTPClient *http = HTTPClient::get_global_ptr();
bool success = false;
while (!core_urls.empty()) {
url = core_urls.back();
core_urls.pop_back();
PT(HTTPChannel) channel = http->get_document(url);
if (!channel->download_to_file(pathname)) {
cerr << "Unable to download " << url << "\n";
} else if (!_coreapi_dll.full_verify(_root_dir)) {
cerr << "Mismatched download for " << url << "\n";
} else {
// successfully downloaded!
success = true;
break;
}
}
if (!success) {
cerr << "Couldn't download core API.\n";
if (!download_core_api()) {
return false;
}
// Since we had to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
is_fresh = true;
}
// Now we've got the DLL. Load it.
@ -795,9 +754,19 @@ get_core_api() {
if (!load_plugin(pathname, contents_filename.to_os_specific(),
_host_url, _verify_contents, _this_platform, _log_dirname,
_log_basename, trusted_environment, _console_environment,
_root_dir, "", cerr)) {
cerr << "Unable to launch core API in " << pathname << "\n";
return false;
_root_dir, _host_dir, _start_dir, cerr)) {
// If we're not sure this is the latest version, make sure it is
// up-to-date, and then try again.
if (is_fresh || !download_core_api() ||
!load_plugin(pathname, contents_filename.to_os_specific(),
_host_url, _verify_contents, _this_platform, _log_dirname,
_log_basename, trusted_environment, _console_environment,
_root_dir, _host_dir, _start_dir, cerr)) {
cerr << "Unable to launch core API in " << pathname << "\n";
return false;
}
}
// Successfully loaded.
@ -822,6 +791,87 @@ get_core_api() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::download_core_api
// Access: Protected
// Description: Downloads the latest version of the core API from
// the plug-in server.
////////////////////////////////////////////////////////////////////
bool Panda3D::
download_core_api() {
// The DLL file needs to be downloaded. Build up our list of
// URL's to attempt to download it from, in reverse order.
string url;
vector_string core_urls;
// Our last act of desperation: hit the original host, with a
// query uniquifier, to break through any caches.
ostringstream strm;
strm << _download_url_prefix << _coreapi_dll.get_filename()
<< "?" << time(NULL);
url = strm.str();
core_urls.push_back(url);
// Before we try that, we'll hit the original host, without a
// uniquifier.
url = _download_url_prefix;
url += _coreapi_dll.get_filename();
core_urls.push_back(url);
// And before we try that, we'll try two mirrors, at random.
vector_string mirrors;
choose_random_mirrors(mirrors, 2);
for (vector_string::iterator si = mirrors.begin();
si != mirrors.end();
++si) {
url = (*si) + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// The very first thing we'll try is the super_mirror, if we have
// one.
if (!_super_mirror_url_prefix.empty()) {
url = _super_mirror_url_prefix + _coreapi_dll.get_filename();
core_urls.push_back(url);
}
// Now pick URL's off the list, and try them, until we have
// success.
Filename pathname = Filename::from_os_specific(_coreapi_dll.get_pathname(_root_dir));
pathname.make_dir();
HTTPClient *http = HTTPClient::get_global_ptr();
bool success = false;
while (!core_urls.empty()) {
url = core_urls.back();
core_urls.pop_back();
PT(HTTPChannel) channel = http->get_document(url);
if (!channel->download_to_file(pathname)) {
cerr << "Unable to download " << url << "\n";
} else if (!_coreapi_dll.full_verify(_root_dir)) {
cerr << "Mismatched download for " << url << "\n";
} else {
// successfully downloaded!
success = true;
break;
}
}
if (!success) {
return false;
}
// Since we had to download some of it, might as well ask the core
// API to check all of it.
if (_verify_contents == P3D_VC_none) {
_verify_contents = P3D_VC_normal;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Panda3D::usage
// Access: Protected

View File

@ -42,12 +42,14 @@ public:
protected:
bool post_arg_processing();
bool get_plugin();
bool download_contents_file(const Filename &contents_filename);
bool read_contents_file(const Filename &contents_filename, bool fresh_download);
void find_host(TiXmlElement *xcontents);
void read_xhost(TiXmlElement *xhost);
void add_mirror(string mirror_url);
void choose_random_mirrors(vector_string &result, int num_mirrors);
bool get_core_api();
bool download_core_api();
void usage();

View File

@ -342,7 +342,7 @@ make_parent_window() {
////////////////////////////////////////////////////////////////////
P3D_instance *Panda3DBase::
create_instance(const string &p3d, bool start_instance,
char **args, int num_args, const int &p3d_offset) {
char **args, int num_args, int p3d_offset) {
// Check to see if the p3d filename we were given is a URL, or a
// local file.
Filename p3d_filename = Filename::from_os_specific(p3d);
@ -356,9 +356,9 @@ create_instance(const string &p3d, bool start_instance,
p3d_filename.make_absolute();
os_p3d_filename = p3d_filename.to_os_specific();
}
}
if (is_local) {
read_p3d_info(p3d_filename);
read_p3d_info(p3d_filename, p3d_offset);
}
// Build up the token list.
@ -454,9 +454,9 @@ delete_instance(P3D_instance *inst) {
// parameters (like width and height).
////////////////////////////////////////////////////////////////////
bool Panda3DBase::
read_p3d_info(const Filename &p3d_filename) {
read_p3d_info(const Filename &p3d_filename, int p3d_offset) {
PT(Multifile) mf = new Multifile;
if (!mf->open_read(p3d_filename)) {
if (!mf->open_read(p3d_filename, p3d_offset)) {
return false;
}
int si = mf->find_subfile("p3d_info.xml");

View File

@ -49,10 +49,10 @@ protected:
P3D_instance *
create_instance(const string &p3d, bool start_instance,
char **args, int num_args, const int &p3d_offset = 0);
char **args, int num_args, int p3d_offset = 0);
void delete_instance(P3D_instance *instance);
bool read_p3d_info(const Filename &p3d_filename);
bool read_p3d_info(const Filename &p3d_filename, int p3d_offset = 0);
bool parse_token(const char *arg);
bool parse_int_pair(const char *arg, int &x, int &y);
string lookup_token(const string &keyword) const;
@ -74,6 +74,7 @@ protected:
string _host_url;
string _root_dir;
string _host_dir;
string _start_dir;
string _log_dirname;
string _log_basename;
string _this_platform;

View File

@ -855,7 +855,7 @@ class Loader(DirectObject):
def loadShader (self, shaderPath, okMissing = False):
shader = ShaderPool.loadShader (shaderPath)
if not shader and not okMissing:
message = 'Could not shader file: %s' % (shaderPath)
message = 'Could not load shader file: %s' % (shaderPath)
raise IOError, message
return shader

View File

@ -1993,7 +1993,7 @@ def pstatcollect(scope, level = None):
try:
if not (__dev__ or config.GetBool('force-pstatcollect', 0)) or \
if not (__dev__ or ConfigVariableBool('force-pstatcollect', False)) or \
not scope:
return decorator

View File

@ -9,6 +9,8 @@ __all__ = ['ShowBase', 'WindowControls']
from panda3d.core import *
from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gui
from panda3d.direct import storeAccessibilityShortcutKeys, allowAccessibilityShortcutKeys
# This needs to be available early for DirectGUI imports
import __builtin__ as builtins
@ -70,6 +72,8 @@ class ShowBase(DirectObject.DirectObject):
if logStackDump or uploadStackDump:
ExceptionVarDump.install(logStackDump, uploadStackDump)
self.__autoGarbageLogging = self.__dev__ and self.config.GetBool('auto-garbage-logging', False)
## The directory containing the main Python file of this application.
self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
@ -289,7 +293,6 @@ class ShowBase(DirectObject.DirectObject):
self.physicsMgrEnabled = 0
self.physicsMgrAngular = 0
self.createBaseAudioManagers()
self.createStats()
self.AppHasAudioFocus = 1
@ -377,6 +380,8 @@ class ShowBase(DirectObject.DirectObject):
else:
ShowBase.notify.info('__dev__ == %s' % __dev__)
self.createBaseAudioManagers()
# set up recording of Functor creation stacks in __dev__
PythonUtil.recordFunctorCreationStacks()
@ -526,9 +531,6 @@ class ShowBase(DirectObject.DirectObject):
del self.winList
del self.pipe
vfs = VirtualFileSystem.getGlobalPtr()
vfs.unmountAll()
def makeDefaultPipe(self, printPipeTypes = True):
"""
Creates the default GraphicsPipe, which will be used to make
@ -2660,7 +2662,7 @@ class ShowBase(DirectObject.DirectObject):
if not properties.getOpen():
# If the user closes the main window, we should exit.
self.notify.info("User closed main window.")
if __dev__ and config.GetBool('auto-garbage-logging', 0):
if self.__autoGarbageLogging:
GarbageReport.b_checkForGarbageLeaks()
self.userExit()
@ -2668,7 +2670,7 @@ class ShowBase(DirectObject.DirectObject):
self.mainWinForeground = 1
elif not properties.getForeground() and self.mainWinForeground:
self.mainWinForeground = 0
if __dev__ and config.GetBool('auto-garbage-logging', 0):
if self.__autoGarbageLogging:
GarbageReport.b_checkForGarbageLeaks()
if properties.getMinimized() and not self.mainWinMinimized:

View File

@ -166,7 +166,7 @@ class Transitions:
self.loadFade()
self.fade.reparentTo(aspect2d, FADE_SORT_INDEX)
self.fade.setColor(self.alphaOn)
elif base.config.GetBool('no-loading-screen',0):
elif ConfigVariableBool('no-loading-screen', False):
if finishIval:
self.transitionIval = finishIval
self.transitionIval.start()

View File

@ -1,7 +1,7 @@
__all__ = ['register', 'sharedPackages',
'reloadSharedPackage', 'reloadSharedPackages']
from panda3d.core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
from panda3d._core import Filename, VirtualFileSystem, VirtualFileMountSystem, OFileStream, copyStream
import sys
import marshal
import imp
@ -25,12 +25,6 @@ sharedPackages = {}
vfs = VirtualFileSystem.getGlobalPtr()
# Possible file types.
FTPythonSource = 0
FTPythonCompiled = 1
FTExtensionModule = 2
FTFrozenModule = 3
compiledExtensions = [ 'pyc', 'pyo' ]
if not __debug__:
# In optimized mode, we prefer loading .pyo files over .pyc files.
@ -44,7 +38,10 @@ class VFSImporter:
(among other places). """
def __init__(self, path):
self.dir_path = Filename.fromOsSpecific(path)
if isinstance(path, Filename):
self.dir_path = Filename(path)
else:
self.dir_path = Filename.fromOsSpecific(path)
def find_module(self, fullname, path = None):
if path is None:
@ -60,7 +57,8 @@ class VFSImporter:
filename.setExtension('py')
vfile = vfs.getFile(filename, True)
if vfile:
return VFSLoader(dir_path, vfile, filename, FTPythonSource)
return VFSLoader(dir_path, vfile, filename,
desc=('.py', 'U', imp.PY_SOURCE))
# If there's no .py file, but there's a .pyc file, load that
# anyway.
@ -69,33 +67,32 @@ class VFSImporter:
filename.setExtension(ext)
vfile = vfs.getFile(filename, True)
if vfile:
return VFSLoader(dir_path, vfile, filename, FTPythonCompiled)
return VFSLoader(dir_path, vfile, filename,
desc=('.'+ext, 'rb', imp.PY_COMPILED))
# Look for a C/C++ extension module.
for desc in imp.get_suffixes():
if desc[2] != imp.C_EXTENSION:
continue
filename = Filename(path)
filename.setExtension(desc[0][1:])
filename = Filename(path + desc[0])
vfile = vfs.getFile(filename, True)
if vfile:
return VFSLoader(dir_path, vfile, filename, FTExtensionModule,
desc = desc)
return VFSLoader(dir_path, vfile, filename, desc=desc)
# Finally, consider a package, i.e. a directory containing
# __init__.py.
filename = Filename(path, '__init__.py')
vfile = vfs.getFile(filename, True)
if vfile:
return VFSLoader(dir_path, vfile, filename, FTPythonSource,
packagePath = path)
return VFSLoader(dir_path, vfile, filename, packagePath=path,
desc=('.py', 'U', imp.PY_SOURCE))
for ext in compiledExtensions:
filename = Filename(path, '__init__.' + ext)
vfile = vfs.getFile(filename, True)
if vfile:
return VFSLoader(dir_path, vfile, filename, FTPythonCompiled,
packagePath = path)
return VFSLoader(dir_path, vfile, filename, packagePath=path,
desc=('.'+ext, 'rb', imp.PY_COMPILED))
#print >>sys.stderr, "not found."
return None
@ -104,22 +101,20 @@ class VFSLoader:
""" The second part of VFSImporter, this is created for a
particular .py file or directory. """
def __init__(self, dir_path, vfile, filename, fileType,
desc = None, packagePath = None):
def __init__(self, dir_path, vfile, filename, desc, packagePath=None):
self.dir_path = dir_path
self.timestamp = None
if vfile:
self.timestamp = vfile.getTimestamp()
self.filename = filename
self.fileType = fileType
self.desc = desc
self.packagePath = packagePath
def load_module(self, fullname, loadingShared = False):
#print >>sys.stderr, "load_module(%s), dir_path = %s, filename = %s" % (fullname, self.dir_path, self.filename)
if self.fileType == FTFrozenModule:
if self.desc[2] == imp.PY_FROZEN:
return self._import_frozen_module(fullname)
if self.fileType == FTExtensionModule:
if self.desc[2] == imp.C_EXTENSION:
return self._import_extension_module(fullname)
# Check if this is a child of a shared package.
@ -137,7 +132,7 @@ class VFSLoader:
code = self._read_code()
if not code:
raise ImportError, 'No Python code in %s' % (fullname)
raise ImportError('No Python code in %s' % (fullname))
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__file__ = self.filename.toOsSpecific()
@ -153,7 +148,7 @@ class VFSLoader:
path = Filename(self.dir_path, Filename.fromOsSpecific(path))
vfile = vfs.getFile(path)
if not vfile:
raise IOError
raise IOError("Could not find '%s'" % (path))
return vfile.readFile(True)
def is_package(self, fullname):
@ -172,8 +167,8 @@ class VFSLoader:
""" Returns the Python source for this file, if it is
available, or None if it is not. May raise IOError. """
if self.fileType == FTPythonCompiled or \
self.fileType == FTExtensionModule:
if self.desc[2] == imp.PY_COMPILED or \
self.desc[2] == imp.C_EXTENSION:
return None
filename = Filename(self.filename)
@ -181,7 +176,7 @@ class VFSLoader:
filename.setText()
vfile = vfs.getFile(filename)
if not vfile:
raise IOError
raise IOError("Could not find '%s'" % (filename))
return vfile.readFile(True)
def _import_extension_module(self, fullname):
@ -231,6 +226,10 @@ class VFSLoader:
#print >>sys.stderr, "importing frozen %s" % (fullname)
module = imp.load_module(fullname, None, fullname,
('', '', imp.PY_FROZEN))
# Workaround for bug in Python 2.
if getattr(module, '__path__', None) == fullname:
module.__path__ = []
return module
def _read_code(self):
@ -239,14 +238,14 @@ class VFSLoader:
ValueError, SyntaxError, or a number of other errors generated
by the low-level system. """
if self.fileType == FTPythonCompiled:
if self.desc[2] == imp.PY_COMPILED:
# It's a pyc file; just read it directly.
pycVfile = vfs.getFile(self.filename, False)
if pycVfile:
return self._loadPyc(pycVfile, None)
raise IOError, 'Could not read %s' % (self.filename)
raise IOError('Could not read %s' % (self.filename))
elif self.fileType == FTExtensionModule:
elif self.desc[2] == imp.C_EXTENSION:
return None
# It's a .py file (or an __init__.py file; same thing). Read
@ -282,16 +281,21 @@ class VFSLoader:
code = None
data = vfile.readFile(True)
if data[:4] == imp.get_magic():
if data[:4] != imp.get_magic():
raise ValueError("Bad magic number in %s" % (vfile))
if sys.version_info >= (3, 0):
t = int.from_bytes(data[4:8], 'little')
data = data[12:]
else:
t = ord(data[4]) + (ord(data[5]) << 8) + \
(ord(data[6]) << 16) + (ord(data[7]) << 24)
if not timestamp or t == timestamp:
code = marshal.loads(data[8:])
else:
raise ValueError, 'Timestamp wrong on %s' % (vfile)
data = data[8:]
if not timestamp or t == timestamp:
return marshal.loads(data)
else:
raise ValueError, 'Bad magic number in %s' % (vfile)
return code
raise ValueError("Timestamp wrong on %s" % (vfile))
def _compile(self, filename, source):
@ -311,15 +315,16 @@ class VFSLoader:
except IOError:
pass
else:
f.write('\0\0\0\0')
f.write(chr(self.timestamp & 0xff) +
chr((self.timestamp >> 8) & 0xff) +
chr((self.timestamp >> 16) & 0xff) +
chr((self.timestamp >> 24) & 0xff))
f.write(marshal.dumps(code))
f.flush()
f.seek(0, 0)
f.write(imp.get_magic())
if sys.version_info >= (3, 0):
f.write((self.timestamp & 0xffffffff).to_bytes(4, 'little'))
f.write(b'\0\0\0\0')
else:
f.write(chr(self.timestamp & 0xff) +
chr((self.timestamp >> 8) & 0xff) +
chr((self.timestamp >> 16) & 0xff) +
chr((self.timestamp >> 24) & 0xff))
f.write(marshal.dumps(code))
f.close()
return code
@ -389,7 +394,7 @@ class VFSSharedImporter:
""" Returns the directory name that the indicated
conventionally-loaded module must have been loaded from. """
if not hasattr(mod, __file__) or mod.__file__ is None:
if not getattr(mod, '__file__', None):
return None
fullname = mod.__name__
@ -434,6 +439,9 @@ class VFSSharedLoader:
if self.reload:
mod = sys.modules[fullname]
path = mod.__path__ or []
if path == fullname:
# Work around Python bug setting __path__ of frozen modules.
path = []
vfs_shared_path = getattr(mod, '_vfs_shared_path', [])
for loader in self.loaders:
@ -451,11 +459,12 @@ class VFSSharedLoader:
if mod is None:
# If all of them failed to load, raise ImportError.
raise ImportError, message
raise ImportError(message)
# If at least one of them loaded successfully, return the
# union of loaded modules.
mod.__path__ = path
mod.__package__ = fullname
# Also set this special symbol, which records that this is a
# shared package, and also lists the paths we have already
@ -516,7 +525,9 @@ def reloadSharedPackages():
#print >> sys.stderr, "reloadSharedPackages, path = %s, sharedPackages = %s" % (sys.path, sharedPackages.keys())
for fullname in sharedPackages.keys():
# Sort the list, just to make sure parent packages are reloaded
# before child packages are.
for fullname in sorted(sharedPackages.keys()):
mod = sys.modules.get(fullname, None)
if not mod:
continue

View File

@ -8,7 +8,8 @@ import marshal
import imp
import platform
import types
from distutils.sysconfig import PREFIX, get_python_inc, get_python_version
from StringIO import StringIO
from distutils.sysconfig import PREFIX, get_python_inc, get_python_version, get_config_var
# Temporary (?) try..except to protect against unbuilt p3extend_frozen.
try:
@ -17,7 +18,6 @@ except ImportError:
p3extend_frozen = None
from panda3d.core import *
from pandac.extension_native_helpers import dll_suffix, dll_ext
# Check to see if we are running python_d, which implies we have a
# debug build, and we have to build the module with debug options.
@ -31,14 +31,12 @@ isDebugBuild = (python.lower().endswith('_d'))
# must be frozen in any main.exe.
startupModules = [
'site', 'sitecustomize', 'os', 'encodings.cp1252',
'org',
'encodings.latin_1', 'encodings.utf_8', 'io', 'org',
]
# These are missing modules that we've reported already this session.
reportedMissing = {}
# Our own Python source trees to watch out for.
sourceTrees = ['direct']
class CompilationEnvironment:
""" Create an instance of this class to record the commands to
@ -64,7 +62,7 @@ class CompilationEnvironment:
# Paths to Python stuff.
self.Python = None
self.PythonIPath = get_python_inc()
self.PythonVersion = get_python_version()
self.PythonVersion = get_config_var("LDVERSION") or get_python_version()
# The VC directory of Microsoft Visual Studio (if relevant)
self.MSVC = None
@ -445,7 +443,7 @@ extend_frozen_modules(const struct _frozen *new_modules, int new_count) {
}
%(dllexport)svoid init%(moduleName)s() {
extend_frozen_modules(_PyImport_FrozenModules, %(newcount)s);
extend_frozen_modules(_PyImport_FrozenModules, sizeof(_PyImport_FrozenModules) / sizeof(struct _frozen));
Py_InitModule("%(moduleName)s", nullMethods);
}
"""
@ -458,7 +456,7 @@ programFile = """
%(moduleDefs)s
static struct _frozen _PyImport_FrozenModules[] = {
struct _frozen _PyImport_FrozenModules[] = {
%(moduleList)s
{NULL, NULL, 0}
};
@ -485,7 +483,7 @@ okMissing = [
'Carbon.Folder', 'Carbon.Folders', 'HouseGlobals', 'Carbon.File',
'MacOS', '_emx_link', 'ce', 'mac', 'org.python.core', 'os.path',
'os2', 'posix', 'pwd', 'readline', 'riscos', 'riscosenviron',
'riscospath', 'dbm', 'fcntl', 'win32api',
'riscospath', 'dbm', 'fcntl', 'win32api', 'usercustomize',
'_winreg', 'ctypes', 'ctypes.wintypes', 'nt','msvcrt',
'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios',
'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
@ -498,7 +496,8 @@ class Freezer:
def __init__(self, moduleName, filename = None,
implicit = False, guess = False,
exclude = False, forbid = False,
allowChildren = False, fromSource = None):
allowChildren = False, fromSource = None,
text = None):
# The Python module name.
self.moduleName = moduleName
@ -533,6 +532,9 @@ class Freezer:
# record came from, supplied by the caller.
self.fromSource = fromSource
# If this is set, it contains Python code of the module.
self.text = text
# Some sanity checks.
if not self.exclude:
self.allowChildren = True
@ -609,20 +611,14 @@ class Freezer:
self.mf = None
# Make sure we know how to find "direct".
for sourceTree in sourceTrees:
try:
module = __import__(sourceTree)
except:
pass
# Actually, make sure we know how to find all of the
# already-imported modules. (Some of them might do their own
# special path mangling.)
for moduleName, module in sys.modules.items():
if module and hasattr(module, '__path__'):
path = getattr(module, '__path__')
modulefinder.AddPackagePath(moduleName, path[0])
if path:
modulefinder.AddPackagePath(moduleName, path[0])
def excludeFrom(self, freezer):
""" Excludes all modules that have already been processed by
@ -749,7 +745,8 @@ class Freezer:
return modules
def addModule(self, moduleName, implicit = False, newName = None,
filename = None, guess = False, fromSource = None):
filename = None, guess = False, fromSource = None,
text = None):
""" Adds a module to the list of modules to be exported by
this tool. If implicit is true, it is OK if the module does
not actually exist.
@ -805,7 +802,7 @@ class Freezer:
# It's actually a regular module.
self.modules[newParentName] = self.ModuleDef(
parentName, implicit = implicit, guess = guess,
fromSource = fromSource)
fromSource = fromSource, text = text)
else:
# Now get all the py files in the parent directory.
@ -820,9 +817,9 @@ class Freezer:
# A normal, explicit module name.
self.modules[newName] = self.ModuleDef(
moduleName, filename = filename, implicit = implicit,
guess = guess, fromSource = fromSource)
guess = guess, fromSource = fromSource, text = text)
def done(self, compileToExe = False):
def done(self, addStartupModules = False):
""" Call this method after you have added all modules with
addModule(). You may then call generateCode() or
writeMultifile() to dump the resulting output. After a call
@ -833,7 +830,9 @@ class Freezer:
# If we are building an exe, we also need to implicitly
# bring in Python's startup modules.
if compileToExe:
if addStartupModules:
self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True)
for moduleName in startupModules:
if moduleName not in self.modules:
self.modules[moduleName] = self.ModuleDef(moduleName, implicit = True)
@ -971,7 +970,10 @@ class Freezer:
stuff = ("", "rb", imp.PY_COMPILED)
self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
else:
fp = open(pathname, modulefinder.READ_MODE)
if mdef.text:
fp = StringIO(mdef.text)
else:
fp = open(pathname, 'U')
stuff = ("", "r", imp.PY_SOURCE)
self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
@ -1063,8 +1065,12 @@ class Freezer:
def __addPyc(self, multifile, filename, code, compressionLevel):
if code:
data = imp.get_magic() + '\0\0\0\0' + \
marshal.dumps(code)
data = imp.get_magic() + b'\0\0\0\0'
if sys.version_info >= (3, 0):
data += b'\0\0\0\0'
data += marshal.dumps(code)
stream = StringStream(data)
multifile.addSubfile(filename, stream, compressionLevel)
@ -1206,22 +1212,9 @@ class Freezer:
multifile.flush()
multifile.repack()
def generateCode(self, basename, compileToExe = False):
""" After a call to done(), this freezes all of the
accumulated python code into either an executable program (if
compileToExe is true) or a dynamic library (if compileToExe is
false). The basename is the name of the file to write,
without the extension.
The return value is the newly-generated filename, including
the filename extension. Additional extension modules are
listed in self.extras. """
if compileToExe:
# We must have a __main__ module to make an exe file.
if not self.__writingModule('__main__'):
message = "Can't generate an executable without a __main__ module."
raise StandardError, message
def writeCode(self, filename, initCode = ""):
""" After a call to done(), this freezes all of the accumulated
Python code into a C source file. """
self.__replacePaths()
@ -1239,38 +1232,57 @@ class Freezer:
# Allow importing this module.
module = self.mf.modules.get(origName, None)
code = getattr(module, "__code__", None)
if not code and moduleName in startupModules:
if code:
code = marshal.dumps(code)
mangledName = self.mangleName(moduleName)
moduleDefs.append(self.makeModuleDef(mangledName, code))
moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, module))
elif moduleName in startupModules:
# Forbid the loading of this startup module.
moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
else:
if origName in sourceTrees:
# This is one of Panda3D's own Python source
# trees. These are a special case: we don't
# compile the __init__.py files within them,
# since their only purpose is to munge the
# __path__ variable anyway. Instead, we
# pretend the __init__.py files are empty.
code = compile('', moduleName, 'exec')
if code:
code = marshal.dumps(code)
mangledName = self.mangleName(moduleName)
moduleDefs.append(self.makeModuleDef(mangledName, code))
moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, module))
# This is a module with no associated Python
# code. It must be an extension module. Get the
# filename.
extensionFilename = getattr(module, '__file__', None)
if extensionFilename:
self.extras.append((moduleName, extensionFilename))
else:
# It doesn't even have a filename; it must
# be a built-in module. No worries about
# this one, then.
pass
# This is a module with no associated Python
# code. It must be an extension module. Get the
# filename.
extensionFilename = getattr(module, '__file__', None)
if extensionFilename:
self.extras.append((moduleName, extensionFilename))
else:
# It doesn't even have a filename; it must
# be a built-in module. No worries about
# this one, then.
pass
text = programFile % {
'moduleDefs': '\n'.join(moduleDefs),
'moduleList': '\n'.join(moduleList),
'initCode': initCode
}
if filename is not None:
file = open(filename, 'w')
file.write(text)
file.close()
def generateCode(self, basename, compileToExe = False):
""" After a call to done(), this freezes all of the
accumulated python code into either an executable program (if
compileToExe is true) or a dynamic library (if compileToExe is
false). The basename is the name of the file to write,
without the extension.
The return value is the newly-generated filename, including
the filename extension. Additional extension modules are
listed in self.extras. """
if compileToExe:
# We must have a __main__ module to make an exe file.
if not self.__writingModule('__main__'):
message = "Can't generate an executable without a __main__ module."
raise StandardError, message
filename = basename + self.sourceExtension
@ -1309,21 +1321,12 @@ class Freezer:
initCode = dllInitCode % {
'moduleName' : os.path.basename(basename),
'newcount' : len(moduleList),
'dllexport' : dllexport,
'dllimport' : dllimport,
}
compileFunc = self.cenv.compileDll
text = programFile % {
'moduleDefs' : '\n'.join(moduleDefs),
'moduleList' : '\n'.join(moduleList),
'initCode' : initCode,
}
file = open(filename, 'w')
file.write(text)
file.close()
self.writeCode(filename, initCode=initCode)
try:
compileFunc(filename, basename)
@ -1342,7 +1345,10 @@ class Freezer:
for i in range(0, len(code), 16):
result += '\n '
for c in code[i:i+16]:
result += ('%d,' % ord(c))
if isinstance(c, int): # Python 3
result += ('%d,' % c)
else: # Python 2
result += ('%d,' % ord(c))
result += '\n};\n'
return result
@ -1379,9 +1385,13 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
def __init__(self, *args, **kw):
modulefinder.ModuleFinder.__init__(self, *args, **kw)
def find_module(self, name, path, parent=None):
def find_module(self, name, path, *args, **kwargs):
if imp.is_frozen(name):
# Don't pick up modules that are frozen into p3dpython.
raise ImportError("'%s' is a frozen module" % (name))
try:
return modulefinder.ModuleFinder.find_module(self, name, path, parent = parent)
return modulefinder.ModuleFinder.find_module(self, name, path, *args, **kwargs)
except ImportError:
# It wasn't found through the normal channels. Maybe it's
# one of ours, or maybe it's frozen?
@ -1394,15 +1404,6 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
# It's a frozen module.
return (None, name, ('', '', imp.PY_FROZEN))
# Look for a dtool extension. This loop is roughly lifted
# from extension_native_helpers.Dtool_PreloadDLL().
filename = name + dll_suffix + dll_ext
for dir in sys.path + [sys.prefix]:
lib = os.path.join(dir, filename)
if os.path.exists(lib):
file = open(lib, 'rb')
return (file, lib, (dll_ext, 'rb', imp.C_EXTENSION))
message = "DLL loader cannot find %s." % (name)
raise ImportError, message

View File

@ -10,7 +10,8 @@ class Rope(NodePath):
thick lines built from triangle strips.
"""
showRope = base.config.GetBool('show-rope', 1)
showRope = ConfigVariableBool('show-rope', True, \
"Set this to false to deactivate the display of ropes.")
def __init__(self, name = 'Rope'):
self.ropeNode = RopeNode(name)
@ -18,6 +19,9 @@ class Rope(NodePath):
self.ropeNode.setCurve(self.curve)
NodePath.__init__(self, self.ropeNode)
self.name = name
self.order = 0
self.verts = []
self.knots = None
def setup(self, order, verts, knots = None):
"""This must be called to define the shape of the curve

View File

@ -40,6 +40,11 @@ Options:
of the __path__ variable, and thus must be actually imported to
determine the true value of __path__.
-s
Adds the standard set of modules that are necessary for embedding
the Python interpreter. Implicitly set if an executable is
generated.
"""
import getopt
@ -58,9 +63,10 @@ def usage(code, msg = ''):
freezer = FreezeTool.Freezer()
basename = None
addStartupModules = False
try:
opts, args = getopt.getopt(sys.argv[1:], 'o:i:x:p:h')
opts, args = getopt.getopt(sys.argv[1:], 'o:i:x:p:sh')
except getopt.error, msg:
usage(1, msg)
@ -76,48 +82,57 @@ for opt, arg in opts:
elif opt == '-p':
for module in arg.split(','):
freezer.handleCustomPath(module)
elif opt == '-s':
addStartupModules = True
elif opt == '-h':
usage(0)
else:
print 'illegal option: ' + flag
sys.exit(1)
if not args:
usage(0)
if not basename:
usage(1, 'You did not specify an output file.')
if len(args) != 1:
if len(args) > 1:
usage(1, 'Only one main file may be specified.')
outputType = 'exe'
bl = basename.lower()
if bl.endswith('.mf'):
outputType = 'mf'
elif bl.endswith('.c'):
outputType = 'c'
elif bl.endswith('.dll') or bl.endswith('.pyd') or bl.endswith('.so'):
basename = os.path.splitext(basename)[0]
outputType = 'dll'
elif bl.endswith('.exe'):
basename = os.path.splitext(basename)[0]
startfile = args[0]
startmod = startfile
if startfile.endswith('.py') or startfile.endswith('.pyw') or \
startfile.endswith('.pyc') or startfile.endswith('.pyo'):
startmod = os.path.splitext(startfile)[0]
compileToExe = False
if outputType == 'dll':
freezer.addModule(startmod, filename = startfile)
else:
freezer.addModule('__main__', filename = startfile)
compileToExe = True
if args:
startfile = args[0]
startmod = startfile
if startfile.endswith('.py') or startfile.endswith('.pyw') or \
startfile.endswith('.pyc') or startfile.endswith('.pyo'):
startmod = os.path.splitext(startfile)[0]
freezer.done(compileToExe = compileToExe)
if outputType == 'dll' or outputType == 'c':
freezer.addModule(startmod, filename = startfile)
else:
freezer.addModule('__main__', filename = startfile)
compileToExe = True
addStartupModules = True
elif outputType == 'exe':
# We must have a main module when making an executable.
usage(0)
freezer.done(addStartupModules = addStartupModules)
if outputType == 'mf':
freezer.writeMultifile(basename)
elif outputType == 'c':
freezer.writeCode(basename)
else:
freezer.generateCode(basename, compileToExe = compileToExe)

View File

@ -5,150 +5,208 @@ SIMPLE_THREADS model, by avoiding blocking all threads while waiting
for I/O to complete. """
__all__ = [
'file', 'open', 'listdir', 'walk', 'join',
'open', 'listdir', 'walk', 'join',
'isfile', 'isdir', 'exists', 'lexists', 'getmtime', 'getsize',
'execfile',
]
from panda3d import core
import types
import panda3d._core as core
import sys
import os
import io
import encodings
from posixpath import join
_vfs = core.VirtualFileSystem.getGlobalPtr()
class file:
def __init__(self, filename, mode = 'r', bufsize = None,
autoUnwrap = False):
self.__stream = None
self.__needsVfsClose = False
self.__reader = None
self.__writer = None
self.closed = True
self.encoding = None
self.errors = None
self.__lastWrite = False
if sys.version_info < (3, 0):
# Python 3 defines these subtypes of IOError, but Python 2 doesn't.
FileNotFoundError = IOError
IsADirectoryError = IOError
FileExistsError = IOError
PermissionError = IOError
self.mode = mode
self.name = None
self.filename = None
self.newlines = None
self.softspace = False
readMode = False
writeMode = False
def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True):
if sys.version_info >= (3, 0):
# Python 3 is much stricter than Python 2, which lets
# unknown flags fall through.
for ch in mode:
if ch not in 'rwxabt+U':
raise ValueError("invalid mode: '%s'" % (mode))
if isinstance(filename, core.Istream) or isinstance(filename, core.Ostream):
# If we were given a stream instead of a filename, assign
# it directly.
self.__stream = filename
readMode = isinstance(filename, core.Istream)
writeMode = isinstance(filename, core.Ostream)
creating = 'x' in mode
writing = 'w' in mode
appending = 'a' in mode
updating = '+' in mode
binary = 'b' in mode
universal = 'U' in mode
reading = universal or 'r' in mode
elif isinstance(filename, core.VirtualFile):
if binary and 't' in mode:
raise ValueError("can't have text and binary mode at once")
if creating + reading + writing + appending > 1:
raise ValueError("must have exactly one of create/read/write/append mode")
if binary:
if encoding:
raise ValueError("binary mode doesn't take an encoding argument")
if errors:
raise ValueError("binary mode doesn't take an errors argument")
if newline:
raise ValueError("binary mode doesn't take a newline argument")
if isinstance(file, core.Istream) or isinstance(file, core.Ostream):
# If we were given a stream instead of a filename, assign
# it directly.
raw = StreamIOWrapper(file)
raw.mode = mode
else:
vfile = None
if isinstance(file, core.VirtualFile):
# We can also "open" a VirtualFile object for reading.
self.__stream = filename.openReadFile(autoUnwrap)
if not self.__stream:
message = 'Could not read virtual file %s' % (repr(filename))
raise IOError, message
self.__needsVfsClose = True
readMode = True
vfile = file
filename = vfile.getFilename()
elif isinstance(file, unicode):
# If a raw string is given, assume it's an os-specific
# filename.
filename = core.Filename.fromOsSpecificW(file)
elif isinstance(file, str):
filename = core.Filename.fromOsSpecific(file)
else:
# If a Filename is given, make a writable copy anyway.
filename = core.Filename(file)
if binary or sys.version_info >= (3, 0):
filename.setBinary()
else:
filename.setText()
if not vfile:
vfile = _vfs.getFile(filename)
if not vfile:
if reading:
raise FileNotFoundError("No such file or directory: '%s'" % (filename))
vfile = _vfs.createFile(filename)
if not vfile:
raise IOError("Failed to create file: '%s'" % (filename))
elif creating:
# In 'creating' mode, we have to raise FileExistsError
# if the file already exists. Otherwise, it's the same
# as 'writing' mode.
raise FileExistsError("File exists: '%s'" % (filename))
elif vfile.isDirectory():
raise IsADirectoryError("Is a directory: '%s'" % (filename))
# Actually open the streams.
if reading:
if updating:
stream = vfile.openReadWriteFile(False)
else:
stream = vfile.openReadFile(False)
if not stream:
raise IOError("Could not open %s for reading" % (filename))
elif writing or creating:
if updating:
stream = vfile.openReadWriteFile(True)
else:
stream = vfile.openWriteFile(False, True)
if not stream:
raise IOError("Could not open %s for writing" % (filename))
elif appending:
if updating:
stream = vfile.openReadAppendFile()
else:
stream = vfile.openAppendFile()
if not stream:
raise IOError("Could not open %s for appending" % (filename))
else:
# Otherwise, we must have been given a filename. Open it.
if isinstance(filename, types.StringTypes):
# If a raw string is given, assume it's an os-specific
# filename.
filename = core.Filename.fromOsSpecific(filename)
else:
# If a Filename is given, make a writable copy anyway.
filename = core.Filename(filename)
raise ValueError("Must have exactly one of create/read/write/append mode and at most one plus")
self.filename = filename
self.name = filename.toOsSpecific()
raw = StreamIOWrapper(stream, needsVfsClose=True)
raw.mode = mode
raw.name = vfile.getFilename().toOsSpecific()
binary = False
if 'b' in mode:
# Strip 'b'. This means a binary file.
i = mode.index('b')
mode = mode[:i] + mode[i + 1:]
binary = True
# If a binary stream was requested, return the stream we've created.
if binary:
return raw
if 'U' in mode:
# Strip 'U'. We don't use it; universal-newline support
# is built into Panda, and can't be changed at runtime.
i = mode.index('U')
mode = mode[:i] + mode[i + 1:]
binary = False
# If we're in Python 2, we don't decode unicode strings by default.
if not encoding and sys.version_info < (3, 0):
return raw
if mode == '':
mode = 'r'
line_buffering = False
if buffering == 1:
line_buffering = True
elif buffering == 0:
raise ValueError("can't have unbuffered text I/O")
# Per Python docs, we insist this is true.
assert mode[0] in 'rwa'
# Otherwise, create a TextIOWrapper object to wrap it.
wrapper = io.TextIOWrapper(raw, encoding, errors, newline, line_buffering)
wrapper.mode = mode
return wrapper
if binary:
filename.setBinary()
else:
filename.setText()
# Actually open the streams.
if mode == 'w':
self.__stream = _vfs.openWriteFile(filename, autoUnwrap, True)
if not self.__stream:
message = 'Could not open %s for writing' % (filename)
raise IOError, message
writeMode = True
if sys.version_info < (3, 0):
# Python 2 had an alias for open() called file().
__all__.append('file')
file = open
elif mode == 'a':
self.__stream = _vfs.openAppendFile(filename)
if not self.__stream:
message = 'Could not open %s for writing' % (filename)
raise IOError, message
writeMode = True
elif mode == 'w+':
self.__stream = _vfs.openReadWriteFile(filename, True)
if not self.__stream:
message = 'Could not open %s for writing' % (filename)
raise IOError, message
readMode = True
writeMode = True
class StreamIOWrapper(io.IOBase):
""" This is a file-like object that wraps around a C++ istream and/or
ostream object. It only deals with binary data; to work with text I/O,
create an io.TextIOWrapper object around this, or use the open()
function that is also provided with this module. """
elif mode == 'a+':
self.__stream = _vfs.openReadAppendFile(filename)
if not self.__stream:
message = 'Could not open %s for writing' % (filename)
raise IOError, message
readMode = True
writeMode = True
def __init__(self, stream, needsVfsClose=False):
self.__stream = stream
self.__needsVfsClose = needsVfsClose
self.__reader = None
self.__writer = None
self.__lastWrite = False
elif mode == 'r+':
self.__stream = _vfs.openReadWriteFile(filename, False)
if not self.__stream:
message = 'Could not open %s for writing' % (filename)
raise IOError, message
readMode = True
writeMode = True
if isinstance(stream, core.Istream):
self.__reader = core.StreamReader(stream, False)
elif mode == 'r':
self.__stream = _vfs.openReadFile(filename, autoUnwrap)
if not self.__stream:
if not _vfs.exists(filename):
message = 'No such file: %s' % (filename)
else:
message = 'Could not open %s for reading' % (filename)
raise IOError, message
readMode = True
self.__needsVfsClose = True
if readMode:
self.__reader = core.StreamReader(self.__stream, False)
if writeMode:
self.__writer = core.StreamWriter(self.__stream, False)
if isinstance(stream, core.Ostream):
self.__writer = core.StreamWriter(stream, False)
self.__lastWrite = True
if sys.version_info >= (3, 0):
# In Python 3, we use appendData, which only accepts bytes.
self.__write = self.__writer.appendData
else:
# In Python 2.7, we also accept unicode objects, which are
# implicitly converted to C++ strings.
self.__write = self.__writer.write
def __del__(self):
self.close()
def __repr__(self):
s = "<direct.stdpy.file.StreamIOWrapper"
if hasattr(self, 'name'):
s += " name='%s'" % (self.name)
if hasattr(self, 'mode'):
s += " mode='%s'" % (self.mode)
s += ">"
return s
def readable(self):
return self.__reader is not None
def writable(self):
return self.__writer is not None
def close(self):
if self.__needsVfsClose:
@ -160,70 +218,51 @@ class file:
_vfs.closeWriteFile(self.__stream)
self.__needsVfsClose = False
self.__stream = None
self.__needsVfsClose = False
self.__reader = None
self.__writer = None
def flush(self):
if self.__stream:
if self.__writer:
self.__stream.clear() # clear eof flag
self.__stream.flush()
def __iter__(self):
return self
def next(self):
line = self.readline()
if line:
return line
raise StopIteration
def read(self, size = -1):
def read(self, size=-1):
if not self.__reader:
if not self.__writer:
# The stream is not even open at all.
message = 'I/O operation on closed file'
raise ValueError, message
raise ValueError("I/O operation on closed file")
# The stream is open only in write mode.
message = 'Attempt to read from write-only stream'
raise IOError, message
raise IOError("Attempt to read from write-only stream")
self.__stream.clear() # clear eof flag
self.__lastWrite = False
if size >= 0:
if size is not None and size >= 0:
result = self.__reader.extractBytes(size)
else:
# Read to end-of-file.
result = ''
result = b''
while not self.__stream.eof():
result += self.__reader.extractBytes(1024)
result += self.__reader.extractBytes(512)
return result
def readline(self, size = -1):
read1 = read
def readline(self, size=-1):
if not self.__reader:
if not self.__writer:
# The stream is not even open at all.
message = 'I/O operation on closed file'
raise ValueError, message
raise ValueError("I/O operation on closed file")
# The stream is open only in write mode.
message = 'Attempt to read from write-only stream'
raise IOError, message
raise IOError("Attempt to read from write-only stream")
self.__stream.clear() # clear eof flag
self.__lastWrite = False
return self.__reader.readline()
def readlines(self, sizehint = -1):
lines = []
line = self.readline()
while line:
lines.append(line)
line = self.readline()
return lines
xreadlines = readlines
def seek(self, offset, whence = 0):
if self.__stream:
self.__stream.clear() # clear eof flag
@ -239,58 +278,43 @@ class file:
else:
if self.__reader:
return self.__stream.tellg()
message = 'I/O operation on closed file'
raise ValueError, message
raise ValueError("I/O operation on closed file")
def truncate(self):
""" Sorry, this isn't supported by Panda's low-level I/O,
because it isn't supported by the standard C++ library. """
raise NotImplementedError
def write(self, str):
def write(self, b):
if not self.__writer:
if not self.__reader:
# The stream is not even open at all.
message = 'I/O operation on closed file'
raise ValueError, message
raise ValueError("I/O operation on closed file")
# The stream is open only in read mode.
message = 'Attempt to write to read-only stream'
raise IOError, message
raise IOError("Attempt to write to read-only stream")
self.__stream.clear() # clear eof flag
self.__writer.appendData(str)
self.__write(b)
self.__lastWrite = True
def writelines(self, lines):
if not self.__writer:
if not self.__reader:
# The stream is not even open at all.
message = 'I/O operation on closed file'
raise ValueError, message
raise ValueError("I/O operation on closed file")
# The stream is open only in read mode.
message = 'Attempt to write to read-only stream'
raise IOError, message
raise IOError("Attempt to write to read-only stream")
self.__stream.clear() # clear eof flag
for line in lines:
self.__writer.appendData(line)
self.__write(line)
self.__lastWrite = True
def __enter__(self):
return self
def __exit__(self, t, v, tb):
self.close()
open = file
def listdir(path):
""" Implements os.listdir over vfs. """
files = []
dirlist = _vfs.scanDirectory(core.Filename.fromOsSpecific(path))
if dirlist is None:
message = 'No such file or directory: %s' % (path)
raise OSError, message
raise OSError("No such file or directory: '%s'" % (path))
for file in dirlist:
files.append(file.getFilename().getBasename())
return files
@ -323,20 +347,6 @@ def walk(top, topdown = True, onerror = None, followlinks = True):
if not topdown:
yield (top, dirnames, filenames)
def join(path, *args):
for part in args:
if part == '':
continue
if part.startswith('/'):
path = part
elif path.endswith('/'):
path = path + part
else:
path = '/'.join((path, part))
return path
def isfile(path):
return _vfs.isRegularFile(core.Filename.fromOsSpecific(path))

View File

@ -19,6 +19,8 @@ import Pmw, os,Placer
from panda3d.core import *
from panda3d.physics import *
from panda3d.direct import getParticlePath
class ParticlePanel(AppShell):
# Override class variables

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -49,214 +49,234 @@ extern int cppyydebug;
REAL = 258,
INTEGER = 259,
CHAR_TOK = 260,
STRING = 261,
SIMPLE_STRING = 261,
SIMPLE_IDENTIFIER = 262,
IDENTIFIER = 263,
TYPENAME_IDENTIFIER = 264,
SCOPING = 265,
TYPEDEFNAME = 266,
ELLIPSIS = 267,
OROR = 268,
ANDAND = 269,
EQCOMPARE = 270,
NECOMPARE = 271,
LECOMPARE = 272,
GECOMPARE = 273,
LSHIFT = 274,
RSHIFT = 275,
POINTSAT_STAR = 276,
DOT_STAR = 277,
UNARY = 278,
UNARY_NOT = 279,
UNARY_NEGATE = 280,
UNARY_MINUS = 281,
UNARY_STAR = 282,
UNARY_REF = 283,
POINTSAT = 284,
SCOPE = 285,
PLUSPLUS = 286,
MINUSMINUS = 287,
TIMESEQUAL = 288,
DIVIDEEQUAL = 289,
MODEQUAL = 290,
PLUSEQUAL = 291,
MINUSEQUAL = 292,
OREQUAL = 293,
ANDEQUAL = 294,
XOREQUAL = 295,
LSHIFTEQUAL = 296,
RSHIFTEQUAL = 297,
KW_BEGIN_PUBLISH = 298,
KW_BLOCKING = 299,
KW_BOOL = 300,
KW_CATCH = 301,
KW_CHAR = 302,
KW_CHAR16_T = 303,
KW_CHAR32_T = 304,
KW_CLASS = 305,
KW_CONST = 306,
KW_DELETE = 307,
KW_DOUBLE = 308,
KW_DYNAMIC_CAST = 309,
KW_ELSE = 310,
KW_END_PUBLISH = 311,
KW_ENUM = 312,
KW_EXTENSION = 313,
KW_EXTERN = 314,
KW_EXPLICIT = 315,
KW_PUBLISHED = 316,
KW_FALSE = 317,
KW_FLOAT = 318,
KW_FRIEND = 319,
KW_FOR = 320,
KW_GOTO = 321,
KW_IF = 322,
KW_INLINE = 323,
KW_INT = 324,
KW_LONG = 325,
KW_LONGLONG = 326,
KW_MAKE_PROPERTY = 327,
KW_MAKE_SEQ = 328,
KW_MUTABLE = 329,
KW_NAMESPACE = 330,
KW_NEW = 331,
KW_NOEXCEPT = 332,
KW_OPERATOR = 333,
KW_PRIVATE = 334,
KW_PROTECTED = 335,
KW_PUBLIC = 336,
KW_REGISTER = 337,
KW_RETURN = 338,
KW_SHORT = 339,
KW_SIGNED = 340,
KW_SIZEOF = 341,
KW_STATIC = 342,
KW_STATIC_CAST = 343,
KW_STRUCT = 344,
KW_TEMPLATE = 345,
KW_THROW = 346,
KW_TRUE = 347,
KW_TRY = 348,
KW_TYPEDEF = 349,
KW_TYPENAME = 350,
KW_UNION = 351,
KW_UNSIGNED = 352,
KW_USING = 353,
KW_VIRTUAL = 354,
KW_VOID = 355,
KW_VOLATILE = 356,
KW_WCHAR_T = 357,
KW_WHILE = 358,
START_CPP = 359,
START_CONST_EXPR = 360,
START_TYPE = 361
STRING_LITERAL = 263,
CUSTOM_LITERAL = 264,
IDENTIFIER = 265,
TYPENAME_IDENTIFIER = 266,
SCOPING = 267,
TYPEDEFNAME = 268,
ELLIPSIS = 269,
OROR = 270,
ANDAND = 271,
EQCOMPARE = 272,
NECOMPARE = 273,
LECOMPARE = 274,
GECOMPARE = 275,
LSHIFT = 276,
RSHIFT = 277,
POINTSAT_STAR = 278,
DOT_STAR = 279,
UNARY = 280,
UNARY_NOT = 281,
UNARY_NEGATE = 282,
UNARY_MINUS = 283,
UNARY_STAR = 284,
UNARY_REF = 285,
POINTSAT = 286,
SCOPE = 287,
PLUSPLUS = 288,
MINUSMINUS = 289,
TIMESEQUAL = 290,
DIVIDEEQUAL = 291,
MODEQUAL = 292,
PLUSEQUAL = 293,
MINUSEQUAL = 294,
OREQUAL = 295,
ANDEQUAL = 296,
XOREQUAL = 297,
LSHIFTEQUAL = 298,
RSHIFTEQUAL = 299,
KW_ALIGNAS = 300,
KW_ALIGNOF = 301,
KW_AUTO = 302,
KW_BEGIN_PUBLISH = 303,
KW_BLOCKING = 304,
KW_BOOL = 305,
KW_CATCH = 306,
KW_CHAR = 307,
KW_CHAR16_T = 308,
KW_CHAR32_T = 309,
KW_CLASS = 310,
KW_CONST = 311,
KW_CONSTEXPR = 312,
KW_DECLTYPE = 313,
KW_DEFAULT = 314,
KW_DELETE = 315,
KW_DOUBLE = 316,
KW_DYNAMIC_CAST = 317,
KW_ELSE = 318,
KW_END_PUBLISH = 319,
KW_ENUM = 320,
KW_EXTENSION = 321,
KW_EXTERN = 322,
KW_EXPLICIT = 323,
KW_PUBLISHED = 324,
KW_FALSE = 325,
KW_FLOAT = 326,
KW_FRIEND = 327,
KW_FOR = 328,
KW_GOTO = 329,
KW_IF = 330,
KW_INLINE = 331,
KW_INT = 332,
KW_LONG = 333,
KW_LONGLONG = 334,
KW_MAKE_PROPERTY = 335,
KW_MAKE_SEQ = 336,
KW_MUTABLE = 337,
KW_NAMESPACE = 338,
KW_NEW = 339,
KW_NOEXCEPT = 340,
KW_NULLPTR = 341,
KW_OPERATOR = 342,
KW_PRIVATE = 343,
KW_PROTECTED = 344,
KW_PUBLIC = 345,
KW_REGISTER = 346,
KW_RETURN = 347,
KW_SHORT = 348,
KW_SIGNED = 349,
KW_SIZEOF = 350,
KW_STATIC = 351,
KW_STATIC_ASSERT = 352,
KW_STATIC_CAST = 353,
KW_STRUCT = 354,
KW_TEMPLATE = 355,
KW_THROW = 356,
KW_TRUE = 357,
KW_TRY = 358,
KW_TYPEDEF = 359,
KW_TYPENAME = 360,
KW_UNION = 361,
KW_UNSIGNED = 362,
KW_USING = 363,
KW_VIRTUAL = 364,
KW_VOID = 365,
KW_VOLATILE = 366,
KW_WCHAR_T = 367,
KW_WHILE = 368,
START_CPP = 369,
START_CONST_EXPR = 370,
START_TYPE = 371
};
#endif
/* Tokens. */
#define REAL 258
#define INTEGER 259
#define CHAR_TOK 260
#define STRING 261
#define SIMPLE_STRING 261
#define SIMPLE_IDENTIFIER 262
#define IDENTIFIER 263
#define TYPENAME_IDENTIFIER 264
#define SCOPING 265
#define TYPEDEFNAME 266
#define ELLIPSIS 267
#define OROR 268
#define ANDAND 269
#define EQCOMPARE 270
#define NECOMPARE 271
#define LECOMPARE 272
#define GECOMPARE 273
#define LSHIFT 274
#define RSHIFT 275
#define POINTSAT_STAR 276
#define DOT_STAR 277
#define UNARY 278
#define UNARY_NOT 279
#define UNARY_NEGATE 280
#define UNARY_MINUS 281
#define UNARY_STAR 282
#define UNARY_REF 283
#define POINTSAT 284
#define SCOPE 285
#define PLUSPLUS 286
#define MINUSMINUS 287
#define TIMESEQUAL 288
#define DIVIDEEQUAL 289
#define MODEQUAL 290
#define PLUSEQUAL 291
#define MINUSEQUAL 292
#define OREQUAL 293
#define ANDEQUAL 294
#define XOREQUAL 295
#define LSHIFTEQUAL 296
#define RSHIFTEQUAL 297
#define KW_BEGIN_PUBLISH 298
#define KW_BLOCKING 299
#define KW_BOOL 300
#define KW_CATCH 301
#define KW_CHAR 302
#define KW_CHAR16_T 303
#define KW_CHAR32_T 304
#define KW_CLASS 305
#define KW_CONST 306
#define KW_DELETE 307
#define KW_DOUBLE 308
#define KW_DYNAMIC_CAST 309
#define KW_ELSE 310
#define KW_END_PUBLISH 311
#define KW_ENUM 312
#define KW_EXTENSION 313
#define KW_EXTERN 314
#define KW_EXPLICIT 315
#define KW_PUBLISHED 316
#define KW_FALSE 317
#define KW_FLOAT 318
#define KW_FRIEND 319
#define KW_FOR 320
#define KW_GOTO 321
#define KW_IF 322
#define KW_INLINE 323
#define KW_INT 324
#define KW_LONG 325
#define KW_LONGLONG 326
#define KW_MAKE_PROPERTY 327
#define KW_MAKE_SEQ 328
#define KW_MUTABLE 329
#define KW_NAMESPACE 330
#define KW_NEW 331
#define KW_NOEXCEPT 332
#define KW_OPERATOR 333
#define KW_PRIVATE 334
#define KW_PROTECTED 335
#define KW_PUBLIC 336
#define KW_REGISTER 337
#define KW_RETURN 338
#define KW_SHORT 339
#define KW_SIGNED 340
#define KW_SIZEOF 341
#define KW_STATIC 342
#define KW_STATIC_CAST 343
#define KW_STRUCT 344
#define KW_TEMPLATE 345
#define KW_THROW 346
#define KW_TRUE 347
#define KW_TRY 348
#define KW_TYPEDEF 349
#define KW_TYPENAME 350
#define KW_UNION 351
#define KW_UNSIGNED 352
#define KW_USING 353
#define KW_VIRTUAL 354
#define KW_VOID 355
#define KW_VOLATILE 356
#define KW_WCHAR_T 357
#define KW_WHILE 358
#define START_CPP 359
#define START_CONST_EXPR 360
#define START_TYPE 361
#define STRING_LITERAL 263
#define CUSTOM_LITERAL 264
#define IDENTIFIER 265
#define TYPENAME_IDENTIFIER 266
#define SCOPING 267
#define TYPEDEFNAME 268
#define ELLIPSIS 269
#define OROR 270
#define ANDAND 271
#define EQCOMPARE 272
#define NECOMPARE 273
#define LECOMPARE 274
#define GECOMPARE 275
#define LSHIFT 276
#define RSHIFT 277
#define POINTSAT_STAR 278
#define DOT_STAR 279
#define UNARY 280
#define UNARY_NOT 281
#define UNARY_NEGATE 282
#define UNARY_MINUS 283
#define UNARY_STAR 284
#define UNARY_REF 285
#define POINTSAT 286
#define SCOPE 287
#define PLUSPLUS 288
#define MINUSMINUS 289
#define TIMESEQUAL 290
#define DIVIDEEQUAL 291
#define MODEQUAL 292
#define PLUSEQUAL 293
#define MINUSEQUAL 294
#define OREQUAL 295
#define ANDEQUAL 296
#define XOREQUAL 297
#define LSHIFTEQUAL 298
#define RSHIFTEQUAL 299
#define KW_ALIGNAS 300
#define KW_ALIGNOF 301
#define KW_AUTO 302
#define KW_BEGIN_PUBLISH 303
#define KW_BLOCKING 304
#define KW_BOOL 305
#define KW_CATCH 306
#define KW_CHAR 307
#define KW_CHAR16_T 308
#define KW_CHAR32_T 309
#define KW_CLASS 310
#define KW_CONST 311
#define KW_CONSTEXPR 312
#define KW_DECLTYPE 313
#define KW_DEFAULT 314
#define KW_DELETE 315
#define KW_DOUBLE 316
#define KW_DYNAMIC_CAST 317
#define KW_ELSE 318
#define KW_END_PUBLISH 319
#define KW_ENUM 320
#define KW_EXTENSION 321
#define KW_EXTERN 322
#define KW_EXPLICIT 323
#define KW_PUBLISHED 324
#define KW_FALSE 325
#define KW_FLOAT 326
#define KW_FRIEND 327
#define KW_FOR 328
#define KW_GOTO 329
#define KW_IF 330
#define KW_INLINE 331
#define KW_INT 332
#define KW_LONG 333
#define KW_LONGLONG 334
#define KW_MAKE_PROPERTY 335
#define KW_MAKE_SEQ 336
#define KW_MUTABLE 337
#define KW_NAMESPACE 338
#define KW_NEW 339
#define KW_NOEXCEPT 340
#define KW_NULLPTR 341
#define KW_OPERATOR 342
#define KW_PRIVATE 343
#define KW_PROTECTED 344
#define KW_PUBLIC 345
#define KW_REGISTER 346
#define KW_RETURN 347
#define KW_SHORT 348
#define KW_SIGNED 349
#define KW_SIZEOF 350
#define KW_STATIC 351
#define KW_STATIC_ASSERT 352
#define KW_STATIC_CAST 353
#define KW_STRUCT 354
#define KW_TEMPLATE 355
#define KW_THROW 356
#define KW_TRUE 357
#define KW_TRY 358
#define KW_TYPEDEF 359
#define KW_TYPENAME 360
#define KW_UNION 361
#define KW_UNSIGNED 362
#define KW_USING 363
#define KW_VIRTUAL 364
#define KW_VOID 365
#define KW_VOLATILE 366
#define KW_WCHAR_T 367
#define KW_WHILE 368
#define START_CPP 369
#define START_CONST_EXPR 370
#define START_TYPE 371

View File

@ -57,17 +57,22 @@ int yyparse();
static void
yyerror(const string &msg) {
current_lexer->error(msg);
current_lexer->error(msg, current_lexer->_last_token_loc);
}
static void
yyerror(YYLTYPE *loc, const string &msg) {
current_lexer->error(msg, *loc);
}
static void
yyerror(const string &msg, YYLTYPE &loc) {
current_lexer->error(msg, loc.first_line, loc.first_column);
current_lexer->error(msg, loc);
}
static void
yywarning(const string &msg, YYLTYPE &loc) {
current_lexer->warning(msg, loc.first_line, loc.first_column);
current_lexer->warning(msg, loc);
}
static int
@ -194,13 +199,18 @@ pop_struct() {
/* This is a bison-specific declaration to enable recursive calls to
yyparse(). It changes the calling sequence to yylex(), passing
pointers to the current yylval and yylloc. */
%pure_parser
pointers to the current yylval and yylloc. Bison 2.7 introduces a
different syntax that will also pass the current yylloc to yyerror,
but we have to support Bison versions as old as 2.5 for now. */
/*%define api.pure full*/
%pure-parser
%locations
%token <u.real> REAL
%token <u.integer> INTEGER
%token <u.integer> CHAR_TOK
%token <str> STRING SIMPLE_IDENTIFIER
%token <str> SIMPLE_STRING SIMPLE_IDENTIFIER
%token <u.expr> STRING_LITERAL CUSTOM_LITERAL
%token <u.identifier> IDENTIFIER TYPENAME_IDENTIFIER SCOPING
%token <u.type> TYPEDEFNAME
@ -236,6 +246,9 @@ pop_struct() {
%token LSHIFTEQUAL
%token RSHIFTEQUAL
%token KW_ALIGNAS
%token KW_ALIGNOF
%token KW_AUTO
%token KW_BEGIN_PUBLISH
%token KW_BLOCKING
%token KW_BOOL
@ -245,6 +258,9 @@ pop_struct() {
%token KW_CHAR32_T
%token KW_CLASS
%token KW_CONST
%token KW_CONSTEXPR
%token KW_DECLTYPE
%token KW_DEFAULT
%token KW_DELETE
%token KW_DOUBLE
%token KW_DYNAMIC_CAST
@ -271,6 +287,7 @@ pop_struct() {
%token KW_NAMESPACE
%token KW_NEW
%token KW_NOEXCEPT
%token KW_NULLPTR
%token KW_OPERATOR
%token KW_PRIVATE
%token KW_PROTECTED
@ -281,6 +298,7 @@ pop_struct() {
%token KW_SIGNED
%token KW_SIZEOF
%token KW_STATIC
%token KW_STATIC_ASSERT
%token KW_STATIC_CAST
%token KW_STRUCT
%token KW_TEMPLATE
@ -338,7 +356,7 @@ pop_struct() {
%type <u.type> enum_element_type
/*%type <u.type> typedefname*/
%type <u.identifier> name
%type <str> string
%type <u.expr> string_literal
/* We need to treat KW_OPERATOR as a scopable keyword. */
%type <u.identifier> KW_OPERATOR
@ -511,10 +529,31 @@ declaration:
current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
}
}
| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
{
CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
}
| KW_STATIC_ASSERT '(' const_expr ',' string_literal ')'
{
CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) {
stringstream str;
str << *$5;
yywarning("static_assert failed: " + str.str(), @3);
}
}
| KW_STATIC_ASSERT '(' const_expr ')'
{
// This alternative version of static_assert was introduced in C++17.
CPPExpression::Result result = $3->evaluate();
if (result._type == CPPExpression::RT_error) {
yywarning("static_assert requires a constant expression", @3);
} else if (!result.as_boolean()) {
yywarning("static_assert failed", @3);
}
}
;
@ -538,56 +577,60 @@ storage_class:
{
$$ = 0;
}
| storage_class KW_EXTERN
| KW_EXTERN storage_class
{
$$ = $1 | (int)CPPInstance::SC_extern;
$$ = $2 | (int)CPPInstance::SC_extern;
}
| storage_class KW_EXTERN string
| KW_EXTERN SIMPLE_STRING storage_class
{
$$ = $1 | (int)CPPInstance::SC_extern;
if ($3 == "C") {
$$ = $3 | (int)CPPInstance::SC_extern;
if ($2 == "C") {
$$ |= (int)CPPInstance::SC_c_binding;
} else if ($3 == "C++") {
} else if ($2 == "C++") {
$$ &= ~(int)CPPInstance::SC_c_binding;
} else {
yywarning("Ignoring unknown linkage type \"" + $3 + "\"", @3);
yywarning("Ignoring unknown linkage type \"" + $2 + "\"", @2);
}
}
| storage_class KW_STATIC
| KW_STATIC storage_class
{
$$ = $1 | (int)CPPInstance::SC_static;
$$ = $2 | (int)CPPInstance::SC_static;
}
| storage_class KW_INLINE
| KW_INLINE storage_class
{
$$ = $1 | (int)CPPInstance::SC_inline;
$$ = $2 | (int)CPPInstance::SC_inline;
}
| storage_class KW_VIRTUAL
| KW_VIRTUAL storage_class
{
$$ = $1 | (int)CPPInstance::SC_virtual;
$$ = $2 | (int)CPPInstance::SC_virtual;
}
| storage_class KW_EXPLICIT
| KW_EXPLICIT storage_class
{
$$ = $1 | (int)CPPInstance::SC_explicit;
$$ = $2 | (int)CPPInstance::SC_explicit;
}
| storage_class KW_VOLATILE
| KW_REGISTER storage_class
{
$$ = $1 | (int)CPPInstance::SC_volatile;
$$ = $2 | (int)CPPInstance::SC_register;
}
| storage_class KW_MUTABLE
| KW_VOLATILE storage_class
{
$$ = $1 | (int)CPPInstance::SC_mutable;
$$ = $2 | (int)CPPInstance::SC_volatile;
}
| storage_class KW_REGISTER
| KW_MUTABLE storage_class
{
$$ = $1 | (int)CPPInstance::SC_register;
$$ = $2 | (int)CPPInstance::SC_mutable;
}
| storage_class KW_BLOCKING
| KW_CONSTEXPR storage_class
{
$$ = $1 | (int)CPPInstance::SC_blocking;
$$ = $2 | (int)CPPInstance::SC_constexpr;
}
| storage_class KW_EXTENSION
| KW_BLOCKING storage_class
{
$$ = $1 | (int)CPPInstance::SC_extension;
$$ = $2 | (int)CPPInstance::SC_blocking;
}
| KW_EXTENSION storage_class
{
$$ = $2 | (int)CPPInstance::SC_extension;
}
;
@ -771,16 +814,18 @@ function_prototype:
}
formal_parameter_list ')' function_post
{
pop_scope();
CPPType *type;
if ($1->get_simple_name() == current_scope->get_simple_name()) {
if ($1->get_simple_name() == current_scope->get_simple_name() ||
$1->get_simple_name() == string("~") + current_scope->get_simple_name()) {
// This is a constructor, and has no return.
type = new CPPSimpleType(CPPSimpleType::T_void);
} else {
// This isn't a constructor, so it has an implicit return type of
// int.
yywarning("function has no return type, assuming int", @1);
type = new CPPSimpleType(CPPSimpleType::T_int);
}
pop_scope();
CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1);
ii->add_func_modifier($4, $6);
@ -822,7 +867,7 @@ function_prototype:
yyerror("Invalid destructor name: ~" + $2->get_fully_scoped_name(), @2);
} else {
CPPIdentifier *ident =
new CPPIdentifier("~" + $2->get_simple_name(), @2.file);
new CPPIdentifier("~" + $2->get_simple_name(), @2);
delete $2;
CPPType *type;
@ -849,6 +894,9 @@ function_prototype:
{
pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL);
CPPInstanceIdentifier *ii = $4;
@ -864,6 +912,9 @@ function_prototype:
{
pop_scope();
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL);
CPPInstanceIdentifier *ii = $5;
@ -897,7 +948,7 @@ function_prototype:
string name = "operator typecast " + $2->get_simple_name();
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier(name, @1.file);
ident = new CPPIdentifier(name, @2);
} else {
ident->add_name(name);
}
@ -918,7 +969,7 @@ function_prototype:
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator typecast", @1.file);
ident = new CPPIdentifier("operator typecast", @4);
} else {
ident->add_name("operator typecast");
}
@ -1138,6 +1189,7 @@ template_declaration:
{
pop_scope();
}
| KW_TEMPLATE type_like_declaration
;
template_formal_parameters:
@ -1205,6 +1257,9 @@ template_formal_parameter_type:
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL);
}
;
@ -1222,17 +1277,37 @@ instance_identifier:
// like a regular function.
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator "+$2, @2.file);
ident = new CPPIdentifier("operator "+$2, @2);
} else {
ident->_names.push_back("operator "+$2);
}
$$ = new CPPInstanceIdentifier(ident);
}
| KW_OPERATOR SIMPLE_STRING IDENTIFIER
{
// A C++11 literal operator.
if (!$2.empty()) {
yyerror("expected empty string", @2);
}
CPPIdentifier *ident = $1;
if (ident == NULL) {
ident = new CPPIdentifier("operator \"\" "+$3->get_simple_name(), @3);
} else {
ident->_names.push_back("operator \"\" "+$3->get_simple_name());
}
$$ = new CPPInstanceIdentifier(ident);
}
| KW_CONST instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| KW_VOLATILE instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_volatile);
}
| '*' instance_identifier %prec UNARY
{
@ -1394,20 +1469,22 @@ formal_parameter:
{
$$ = new CPPInstance($1, $2, 0, @2.file);
$$->set_initializer($3);
}
| IDENTIFIER formal_parameter_identifier maybe_initialize
{
yywarning("Not a type: " + $1->get_fully_scoped_name(), @1);
CPPType *type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
$$ = new CPPInstance(type, $2, 0, @2.file);
$$->set_initializer($3);
}
| KW_CONST type formal_parameter_identifier maybe_initialize
{
$3->add_modifier(IIT_const);
$$ = new CPPInstance($2, $3, 0, @3.file);
$$->set_initializer($4);
}
| KW_CONST KW_REGISTER type formal_parameter_identifier maybe_initialize
{
$4->add_modifier(IIT_const);
$$ = new CPPInstance($3, $4, 0, @3.file);
$$->set_initializer($5);
}
| KW_REGISTER formal_parameter
{
$$ = $2;
}
| formal_const_expr
{
@ -1435,6 +1512,11 @@ not_paren_formal_parameter_identifier:
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| KW_VOLATILE not_paren_formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_volatile);
}
| '*' not_paren_formal_parameter_identifier %prec UNARY
{
@ -1480,6 +1562,11 @@ formal_parameter_identifier:
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| KW_VOLATILE formal_parameter_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_volatile);
}
| '*' formal_parameter_identifier %prec UNARY
{
@ -1528,6 +1615,11 @@ empty_instance_identifier:
{
$$ = $2;
$$->add_modifier(IIT_const);
}
| KW_VOLATILE empty_instance_identifier %prec UNARY
{
$$ = $2;
$$->add_modifier(IIT_volatile);
}
| '*' empty_instance_identifier %prec UNARY
{
@ -1570,6 +1662,9 @@ type:
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL);
}
| KW_TYPENAME name
@ -1619,6 +1714,19 @@ type:
}
$$ = et;
}
}
| KW_DECLTYPE '(' const_expr ')'
{
$$ = $3->determine_type();
if ($$ == (CPPType *)NULL) {
stringstream str;
str << *$3;
yyerror("could not determine type of " + str.str(), @3);
}
}
| KW_AUTO
{
$$ = new CPPSimpleType(CPPSimpleType::T_auto);
}
;
@ -1630,6 +1738,9 @@ type_decl:
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL);
}
| KW_TYPENAME name
@ -1697,6 +1808,19 @@ type_decl:
}
$$ = et;
}
}
| KW_DECLTYPE '(' const_expr ')'
{
$$ = $3->determine_type();
if ($$ == (CPPType *)NULL) {
stringstream str;
str << *$3;
yyerror("could not determine type of " + str.str(), @3);
}
}
| KW_AUTO
{
$$ = new CPPSimpleType(CPPSimpleType::T_auto);
}
;
@ -1708,6 +1832,9 @@ predefined_type:
| TYPENAME_IDENTIFIER
{
$$ = $1->find_type(current_scope, global_scope, false, current_lexer);
if ($$ == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert($$ != NULL);
}
| KW_TYPENAME name
@ -1980,8 +2107,32 @@ namespace_declaration:
cpp '}'
{
pop_scope();
}
| KW_INLINE KW_NAMESPACE name '{'
{
CPPScope *scope = $3->find_scope(current_scope, global_scope, current_lexer);
if (scope == NULL) {
// This must be a new namespace declaration.
CPPScope *parent_scope =
$3->get_scope(current_scope, global_scope, current_lexer);
if (parent_scope == NULL) {
parent_scope = current_scope;
}
scope = new CPPScope(parent_scope, $3->_names.back(), V_public);
}
CPPNamespace *nspace = new CPPNamespace($3, scope, @2.file);
nspace->_is_inline = true;
current_scope->add_declaration(nspace, global_scope, current_lexer, @2);
current_scope->define_namespace(nspace);
push_scope(scope);
}
cpp '}'
{
pop_scope();
}
| KW_NAMESPACE '{' cpp '}'
| KW_INLINE KW_NAMESPACE '{' cpp '}'
;
using_declaration:
@ -2134,48 +2285,34 @@ code_block:
element:
REAL
{
}
| INTEGER
{
}
| STRING
{
}
| SIMPLE_STRING
| STRING_LITERAL
| CUSTOM_LITERAL
| CHAR_TOK
{
}
| IDENTIFIER
{
}
| TYPENAME_IDENTIFIER
{
}
| SCOPING
{
}
| SIMPLE_IDENTIFIER
{
}
| ELLIPSIS | OROR | ANDAND
| EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE
| LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT
| SCOPE | PLUSPLUS | MINUSMINUS
| TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
| OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
| KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
| KW_WCHAR_T | KW_CLASS | KW_CONST
| KW_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_CATCH
| KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
| KW_CLASS | KW_CONST | KW_CONSTEXPR | KW_DECLTYPE | KW_DEFAULT
| KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
| KW_EXTERN | KW_EXPLICIT | KW_FALSE
| KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
| KW_IF | KW_INLINE | KW_INT
| KW_LONG | KW_MUTABLE | KW_NEW | KW_PRIVATE | KW_PROTECTED
| KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE
| KW_NEW | KW_NULLPTR | KW_OPERATOR | KW_PRIVATE | KW_PROTECTED
| KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_RETURN
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST
| KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME
| KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE
| KW_WHILE
| KW_OPERATOR
| KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_ASSERT
| KW_STATIC_CAST | KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY
| KW_TYPEDEF | KW_TYPENAME | KW_UNION | KW_UNSIGNED | KW_VIRTUAL
| KW_VOID | KW_VOLATILE | KW_WCHAR_T | KW_WHILE
{
}
| '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%'
@ -2236,6 +2373,10 @@ no_angle_bracket_const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| '!' no_angle_bracket_const_expr %prec UNARY
{
@ -2247,15 +2388,7 @@ no_angle_bracket_const_expr:
}
| '-' no_angle_bracket_const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '*' no_angle_bracket_const_expr %prec UNARY
{
@ -2381,6 +2514,9 @@ const_expr:
{
// A constructor call.
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL);
$$ = new CPPExpression(CPPExpression::construct_op(type, $3));
}
@ -2463,6 +2599,10 @@ const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
@ -2482,15 +2622,7 @@ const_expr:
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '*' const_expr %prec UNARY
{
@ -2623,13 +2755,21 @@ const_operand:
{
$$ = new CPPExpression($1);
}
| string
| string_literal
{
$$ = new CPPExpression($1);
$$ = $1;
}
| CUSTOM_LITERAL
{
$$ = $1;
}
| IDENTIFIER
{
$$ = new CPPExpression($1, current_scope, global_scope, current_lexer);
}
| KW_NULLPTR
{
$$ = new CPPExpression(CPPExpression::get_nullptr());
}
;
@ -2660,6 +2800,10 @@ formal_const_expr:
| KW_SIZEOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::sizeof_func($3));
}
| KW_ALIGNOF '(' full_type ')' %prec UNARY
{
$$ = new CPPExpression(CPPExpression::alignof_func($3));
}
| KW_NEW predefined_type %prec UNARY
{
@ -2679,15 +2823,7 @@ formal_const_expr:
}
| '-' const_expr %prec UNARY
{
if ($2->_type == CPPExpression::T_integer) {
$$ = $2;
$$->_u._integer = -$$->_u._integer;
} else if ($2->_type == CPPExpression::T_real) {
$$ = $2;
$$->_u._real = -$$->_u._real;
} else {
$$ = new CPPExpression(UNARY_MINUS, $2);
}
$$ = new CPPExpression(UNARY_MINUS, $2);
}
| '&' const_expr %prec UNARY
{
@ -2816,9 +2952,21 @@ formal_const_operand:
{
$$ = new CPPExpression($1);
}
| string
| string_literal
{
$$ = new CPPExpression($1);
$$ = $1;
}
| CUSTOM_LITERAL
{
$$ = $1;
}
| IDENTIFIER
{
$$ = new CPPExpression($1, current_scope, global_scope, current_lexer);
}
| KW_NULLPTR
{
$$ = new CPPExpression(CPPExpression::get_nullptr());
}
;
@ -2850,6 +2998,9 @@ typedefname:
TYPENAME_IDENTIFIER
{
CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer);
if (type == NULL) {
yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1);
}
assert(type != NULL);
$$ = type;
}
@ -2872,14 +3023,29 @@ name:
}
;
string:
STRING
string_literal:
SIMPLE_STRING
{
$$ = new CPPExpression($1);
}
| STRING_LITERAL
{
$$ = $1;
}
| string STRING
| string_literal SIMPLE_STRING
{
$$ = $1 + $2;
// The right string takes on the literal type of the left.
$$ = $1;
$$->_str += $2;
}
| string_literal STRING_LITERAL
{
// We have to check that the two literal types match up.
$$ = $1;
if ($2->_type != CPPExpression::T_string && $2->_type != $1->_type) {
yywarning("cannot concatenate two string literals of different types", @$);
}
$$->_str += $2->_str;
}
;

View File

@ -68,8 +68,8 @@ class cppyystype {
public:
string str;
union {
int integer;
double real;
unsigned long long integer;
long double real;
CPPScope *scope;
CPPDeclaration *decl;
CPPInstance *instance;

View File

@ -19,6 +19,7 @@
#include "cppConstType.h"
#include "cppScope.h"
#include "cppParser.h"
#include "cppIdentifier.h"
#include "indent.h"
////////////////////////////////////////////////////////////////////
@ -82,6 +83,7 @@ add_element(const string &name, CPPExpression *value) {
inst = new CPPInstance(CPPType::new_type(new CPPConstType(_element_type)), ident);
}
inst->_storage_class |= CPPInstance::SC_constexpr;
_elements.push_back(inst);
if (value == (CPPExpression *)NULL) {
@ -176,7 +178,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
bool any_changed = false;
for (int i = 0; i < _elements.size(); ++i) {
for (size_t i = 0; i < _elements.size(); ++i) {
CPPInstance *elem_rep =
_elements[i]->substitute_decl(subst, current_scope, global_scope)
->as_instance();

View File

@ -201,6 +201,19 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(unsigned long long value) :
CPPDeclaration(CPPFile())
{
_type = T_integer;
_u._integer = value;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Constructor
// Access: Public
@ -220,7 +233,7 @@ CPPExpression(int value) :
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression::
CPPExpression(double value) :
CPPExpression(long double value) :
CPPDeclaration(CPPFile())
{
_type = T_real;
@ -397,6 +410,89 @@ sizeof_func(CPPType *type) {
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named alignof_func constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
alignof_func(CPPType *type) {
CPPExpression expr(0);
expr._type = T_alignof;
expr._u._typecast._to = type;
expr._u._typecast._op1 = NULL;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(unsigned long long value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(long double value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = new CPPExpression(value);
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
literal(CPPExpression *value, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_literal;
expr._u._literal._value = value;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::named raw_literal constructor
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
CPPExpression CPPExpression::
raw_literal(const string &raw, CPPInstance *lit_op) {
CPPExpression expr(0);
expr._type = T_raw_literal;
expr._str = raw;
expr._u._literal._value = (CPPExpression *)NULL;
expr._u._literal._operator = lit_op;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::get_nullptr
// Access: Public, Static
// Description:
////////////////////////////////////////////////////////////////////
const CPPExpression &CPPExpression::
get_nullptr() {
static CPPExpression expr(0);
expr._type = T_nullptr;
return expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPExpression::Destructor
// Access: Public
@ -416,18 +512,29 @@ evaluate() const {
Result r1, r2;
switch (_type) {
case T_nullptr:
return Result((void *)0);
case T_integer:
return Result(_u._integer);
return Result((int)_u._integer);
case T_real:
return Result(_u._real);
return Result((double)_u._real);
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return Result();
case T_variable:
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL) {
// A constexpr variable, which is treated as const.
if (_u._variable->_storage_class & CPPInstance::SC_constexpr) {
return _u._variable->_initializer->evaluate();
}
// A const variable. Fetch its assigned value.
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
@ -468,6 +575,17 @@ evaluate() const {
case T_sizeof:
return Result();
case T_alignof:
if (_u._typecast._to != NULL) {
// Check if the type is defined with an alignas. TODO: this should
// probably be moved to a virtual getter on CPPType.
CPPExtensionType *etype = _u._typecast._to->as_extension_type();
if (etype != NULL && etype->_alignment != NULL) {
return etype->_alignment->evaluate();
}
}
return Result();
case T_binary_operation:
assert(_u._op._op2 != NULL);
r2 = _u._op._op2->evaluate();
@ -503,23 +621,39 @@ evaluate() const {
// long as we can evaluate the second one *and* that comes out
// to be true.
if (_u._op._operator == OROR && r2._type == RT_integer &&
r2.as_integer() != 0) {
r2.as_boolean()) {
return r2;
}
// Ditto for the operator being && and the second one coming out
// false.
if (_u._op._operator == ANDAND && r2._type == RT_integer &&
r2.as_integer() == 0) {
!r2.as_boolean()) {
return r2;
}
// Also for the operator being [] and the operand being a string.
if (_u._op._operator == '[' && r2._type == RT_integer &&
(_u._op._op1->_type == T_string ||
_u._op._op1->_type == T_u8string)) {
int index = (int)r2.as_integer();
if ((size_t)index == _u._op._op1->_str.size()) {
return Result(0);
} else if (index >= 0 && (size_t)index < _u._op._op1->_str.size()) {
return Result(_u._op._op1->_str[(size_t)index]);
} else {
cerr << "array index " << index << " out of bounds of string literal "
<< *_u._op._op1 << "\n";
}
}
return r1;
}
switch (_u._op._operator) {
case UNARY_NOT:
return Result(!r1.as_integer());
return Result(!r1.as_boolean());
case UNARY_NEGATE:
return Result(~r1.as_integer());
@ -569,14 +703,14 @@ evaluate() const {
return Result(r1.as_integer() & r2.as_integer());
case OROR:
if (r1.as_integer()) {
if (r1.as_boolean()) {
return r1;
} else {
return r2;
}
case ANDAND:
if (r1.as_integer()) {
if (r1.as_boolean()) {
return r2;
} else {
return r1;
@ -652,6 +786,10 @@ evaluate() const {
abort();
}
case T_literal:
case T_raw_literal:
return Result();
default:
cerr << "**invalid operand**\n";
abort();
@ -671,25 +809,51 @@ determine_type() const {
CPPType *t1 = (CPPType *)NULL;
CPPType *t2 = (CPPType *)NULL;
CPPType *int_type =
static CPPType *nullptr_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_nullptr));
static CPPType *int_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int));
CPPType *bool_type =
static CPPType *unsigned_long_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int,
CPPSimpleType::F_unsigned |
CPPSimpleType::F_long));
static CPPType *bool_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool));
CPPType *float_type =
static CPPType *float_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double));
CPPType *char_type =
static CPPType *char_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char));
CPPType *const_char_type =
CPPType::new_type(new CPPConstType(char_type));
static CPPType *wchar_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
CPPType *char_star_type =
CPPType::new_type(new CPPPointerType(const_char_type));
static CPPType *char16_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t));
static CPPType *char32_type =
CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t));
static CPPType *char_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char_type))));
static CPPType *wchar_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(wchar_type))));
static CPPType *char16_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char16_type))));
static CPPType *char32_str_type = CPPType::new_type(
new CPPPointerType(CPPType::new_type(new CPPConstType(char32_type))));
switch (_type) {
case T_nullptr:
return nullptr_type;
case T_integer:
return int_type;
@ -697,7 +861,19 @@ determine_type() const {
return float_type;
case T_string:
return char_star_type;
return char_str_type;
case T_wstring:
return wchar_str_type;
case T_u8string:
return char_str_type;
case T_u16string:
return char16_str_type;
case T_u32string:
return char32_str_type;
case T_variable:
return _u._variable->_type;
@ -725,7 +901,11 @@ determine_type() const {
return CPPType::new_type(new CPPPointerType(_u._typecast._to));
case T_sizeof:
return int_type;
case T_alignof:
// Note: this should actually be size_t, but that is defined as a
// typedef in parser-inc. We could try to resolve it, but that's
// hacky. Eh, it's probably not worth the effort to get this right.
return unsigned_long_type;
case T_binary_operation:
case T_trinary_operation:
@ -819,6 +999,18 @@ determine_type() const {
abort();
}
case T_literal:
case T_raw_literal:
if (_u._literal._operator != NULL) {
CPPType *type = _u._literal._operator->_type;
CPPFunctionType *ftype = type->as_function_type();
if (ftype != (CPPFunctionType *)NULL) {
return ftype->_return_type;
}
}
return NULL;
default:
cerr << "**invalid operand**\n";
abort();
@ -842,9 +1034,14 @@ is_fully_specified() const {
}
switch (_type) {
case T_nullptr:
case T_integer:
case T_real:
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return false;
case T_variable:
@ -865,6 +1062,7 @@ is_fully_specified() const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_fully_specified();
case T_trinary_operation:
@ -882,6 +1080,13 @@ is_fully_specified() const {
case T_unary_operation:
return _u._op._op1->is_fully_specified();
case T_literal:
return _u._literal._value->is_fully_specified() &&
_u._literal._operator->is_fully_specified();
case T_raw_literal:
return _u._literal._value->is_fully_specified();
default:
return true;
}
@ -972,6 +1177,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
rep->_u._typecast._to =
_u._typecast._to->substitute_decl(subst, current_scope, global_scope)
->as_type();
@ -1025,6 +1231,9 @@ is_tbd() const {
case T_variable:
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL) {
if (_u._variable->_storage_class & CPPInstance::SC_constexpr) {
return false;
}
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
return false;
@ -1042,6 +1251,7 @@ is_tbd() const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to->is_tbd();
case T_trinary_operation:
@ -1075,6 +1285,10 @@ is_tbd() const {
void CPPExpression::
output(ostream &out, int indent_level, CPPScope *scope, bool) const {
switch (_type) {
case T_nullptr:
out << "nullptr";
break;
case T_integer:
out << _u._integer;
break;
@ -1090,8 +1304,29 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break;
case T_string:
out << '"';
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
{
switch (_type) {
case T_wstring:
out << 'L';
break;
case T_u8string:
out << "u8";
break;
case T_u16string:
out << "u";
break;
case T_u32string:
out << "U";
break;
default:
break;
}
// We don't really care about preserving the encoding for now.
out << '"';
string::const_iterator si;
for (si = _str.begin(); si != _str.end(); ++si) {
switch (*si) {
@ -1135,9 +1370,10 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
if (_u._variable->_type != NULL &&
_u._variable->_initializer != NULL &&
_u._variable->_vis > V_public) {
// A const variable. Fetch its assigned value.
// A constexpr or const variable. Fetch its assigned value.
CPPConstType *const_type = _u._variable->_type->as_const_type();
if (const_type != NULL) {
if ((_u._variable->_storage_class & CPPInstance::SC_constexpr) != 0 ||
const_type != NULL) {
_u._variable->_initializer->output(out, indent_level, scope, false);
break;
}
@ -1193,6 +1429,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")";
break;
case T_alignof:
out << "alignof(";
_u._typecast._to->output(out, indent_level, scope, false);
out << ")";
break;
case T_unary_operation:
switch (_u._op._operator) {
case UNARY_NOT:
@ -1208,9 +1450,8 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
break;
case UNARY_MINUS:
out << "(- ";
out << '-';
_u._op._op1->output(out, indent_level, scope, false);
out << ")";
break;
case UNARY_STAR:
@ -1362,6 +1603,24 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
out << ")";
break;
case T_literal:
_u._literal._value->output(out, indent_level, scope, false);
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
case T_raw_literal:
out << _str;
if (_u._literal._operator != NULL) {
string name = _u._literal._operator->get_simple_name();
assert(name.substr(0, 12) == "operator \"\" ");
out << name.substr(12);
}
break;
default:
out << "(** invalid operand type " << (int)_type << " **)";
}
@ -1456,6 +1715,9 @@ is_equal(const CPPDeclaration *other) const {
}
switch (_type) {
case T_nullptr:
return true;
case T_integer:
return _u._integer == ot->_u._integer;
@ -1463,6 +1725,10 @@ is_equal(const CPPDeclaration *other) const {
return _u._real == ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str == ot->_str;
case T_variable:
@ -1483,6 +1749,7 @@ is_equal(const CPPDeclaration *other) const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to == ot->_u._typecast._to;
case T_unary_operation:
@ -1496,6 +1763,14 @@ is_equal(const CPPDeclaration *other) const {
return *_u._op._op1 == *ot->_u._op._op1 &&
*_u._op._op2 == *ot->_u._op._op2;
case T_literal:
return *_u._literal._value == *ot->_u._literal._value &&
_u._literal._operator == ot->_u._literal._operator;
case T_raw_literal:
return _str == ot->_str &&
_u._literal._operator == ot->_u._literal._operator;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}
@ -1520,6 +1795,9 @@ is_less(const CPPDeclaration *other) const {
}
switch (_type) {
case T_nullptr:
return false;
case T_integer:
return _u._integer < ot->_u._integer;
@ -1527,6 +1805,10 @@ is_less(const CPPDeclaration *other) const {
return _u._real < ot->_u._real;
case T_string:
case T_wstring:
case T_u8string:
case T_u16string:
case T_u32string:
return _str < ot->_str;
case T_variable:
@ -1549,6 +1831,7 @@ is_less(const CPPDeclaration *other) const {
case T_default_construct:
case T_default_new:
case T_sizeof:
case T_alignof:
return _u._typecast._to < ot->_u._typecast._to;
case T_trinary_operation:
@ -1566,6 +1849,18 @@ is_less(const CPPDeclaration *other) const {
case T_unary_operation:
return *_u._op._op1 < *ot->_u._op._op1;
case T_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return *_u._literal._value < *ot->_u._literal._value;
case T_raw_literal:
if (_u._literal._operator != ot->_u._literal._operator) {
return _u._literal._operator < ot->_u._literal._operator;
}
return _str < ot->_str;
default:
cerr << "(** invalid operand type " << (int)_type << " **)";
}

View File

@ -30,9 +30,10 @@ class CPPFunctionGroup;
////////////////////////////////////////////////////////////////////
class CPPExpression : public CPPDeclaration {
public:
CPPExpression(unsigned long long value);
CPPExpression(int value);
CPPExpression(const string &value);
CPPExpression(double value);
CPPExpression(long double value);
CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
CPPScope *global_scope, CPPPreprocessor *error_sink = NULL);
CPPExpression(int unary_operator, CPPExpression *op1);
@ -43,6 +44,14 @@ public:
static CPPExpression construct_op(CPPType *type, CPPExpression *op1);
static CPPExpression new_op(CPPType *type, CPPExpression *op1 = NULL);
static CPPExpression sizeof_func(CPPType *type);
static CPPExpression alignof_func(CPPType *type);
static CPPExpression literal(unsigned long long value, CPPInstance *lit_op);
static CPPExpression literal(long double value, CPPInstance *lit_op);
static CPPExpression literal(CPPExpression *value, CPPInstance *lit_op);
static CPPExpression raw_literal(const string &raw, CPPInstance *lit_op);
static const CPPExpression &get_nullptr();
~CPPExpression();
@ -92,9 +101,14 @@ public:
enum Type {
T_nullptr,
T_integer,
T_real,
T_string,
T_wstring,
T_u8string,
T_u16string,
T_u32string,
T_variable,
T_function,
T_unknown_ident,
@ -104,16 +118,19 @@ public:
T_new,
T_default_new,
T_sizeof,
T_alignof,
T_unary_operation,
T_binary_operation,
T_trinary_operation,
T_literal,
T_raw_literal,
};
Type _type;
string _str;
union {
int _integer;
double _real;
unsigned long long _integer;
long double _real;
CPPInstance *_variable;
CPPFunctionGroup *_fgroup;
CPPIdentifier *_ident;
@ -131,6 +148,11 @@ public:
CPPExpression *_op2;
CPPExpression *_op3;
} _op;
class {
public:
CPPInstance *_operator;
CPPExpression *_value;
} _literal;
} _u;
protected:
@ -146,5 +168,3 @@ operator << (ostream &out, const CPPExpression::Result &result) {
}
#endif

View File

@ -29,7 +29,8 @@ CPPExtensionType(CPPExtensionType::Type type,
CPPIdentifier *ident, CPPScope *current_scope,
const CPPFile &file) :
CPPType(file),
_type(type), _ident(ident)
_type(type), _ident(ident),
_alignment(NULL)
{
if (_ident != NULL) {
_ident->_native_scope = current_scope;

View File

@ -65,9 +65,9 @@ public:
virtual CPPExtensionType *as_extension_type();
Type _type;
CPPIdentifier *_ident;
CPPExpression *_alignment;
};
ostream &operator << (ostream &out, CPPExtensionType::Type type);

View File

@ -28,7 +28,39 @@
// Description:
////////////////////////////////////////////////////////////////////
CPPIdentifier::
CPPIdentifier(const string &name, const CPPFile &file) : _file(file) {
CPPIdentifier(const string &name, const CPPFile &file) {
_names.push_back(CPPNameComponent(name));
_native_scope = (CPPScope *)NULL;
_loc.first_line = 0;
_loc.first_column = 0;
_loc.last_line = 0;
_loc.last_column = 0;
_loc.file = file;
}
////////////////////////////////////////////////////////////////////
// Function: CPPIdentifier::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPIdentifier::
CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) {
_names.push_back(name);
_native_scope = (CPPScope *)NULL;
_loc.first_line = 0;
_loc.first_column = 0;
_loc.last_line = 0;
_loc.last_column = 0;
_loc.file = file;
}
////////////////////////////////////////////////////////////////////
// Function: CPPIdentifier::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPIdentifier::
CPPIdentifier(const string &name, const cppyyltype &loc) : _loc(loc) {
_names.push_back(CPPNameComponent(name));
_native_scope = (CPPScope *)NULL;
}
@ -39,7 +71,7 @@ CPPIdentifier(const string &name, const CPPFile &file) : _file(file) {
// Description:
////////////////////////////////////////////////////////////////////
CPPIdentifier::
CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) : _file(file) {
CPPIdentifier(const CPPNameComponent &name, const cppyyltype &loc) : _loc(loc) {
_names.push_back(name);
_native_scope = (CPPScope *)NULL;
}
@ -155,6 +187,12 @@ get_local_name(CPPScope *scope) const {
// last name.
CPPScope *my_scope = get_scope(scope, NULL);
// Strip off template scopes, since they don't add anything
// particularly meaningful to the local name.
while (my_scope != NULL && my_scope->as_template_scope() != NULL) {
my_scope = my_scope->get_parent_scope();
}
if (my_scope == NULL) {
result = get_fully_scoped_name();
} else if (my_scope == scope) {
@ -256,7 +294,8 @@ get_scope(CPPScope *current_scope, CPPScope *global_scope,
if (error_sink != NULL) {
error_sink->error("Symbol " + _names[i].get_name() +
" is not a known scope in " +
scope->get_fully_scoped_name());
scope->get_fully_scoped_name(),
_loc);
}
return (CPPScope *)NULL;
}
@ -302,7 +341,8 @@ get_scope(CPPScope *current_scope, CPPScope *global_scope,
if (error_sink != NULL) {
error_sink->error("Symbol " + _names[i].get_name() +
" is not a known scope in " +
scope->get_fully_scoped_name());
scope->get_fully_scoped_name(),
_loc);
}
return (CPPScope *)NULL;
}
@ -429,7 +469,12 @@ find_symbol(CPPScope *current_scope, CPPScope *global_scope,
CPPDeclaration *sym;
if (!_names.back().has_templ()) {
sym = scope->find_symbol(get_simple_name());
if (_names.size() > 1 && scope->get_simple_name() == get_simple_name()) {
// An identifier like Class::Class always refers to the class constructor.
sym = scope->get_struct_type()->get_constructor();
} else {
sym = scope->find_symbol(get_simple_name());
}
} else {
sym = scope->find_template(get_simple_name());
@ -465,7 +510,12 @@ find_symbol(CPPScope *current_scope, CPPScope *global_scope,
CPPDeclaration *sym;
if (!_names.back().has_templ()) {
sym = scope->find_symbol(get_simple_name());
if (_names.size() > 1 && scope->get_simple_name() == get_simple_name()) {
// An identifier like Class::Class always refers to the class constructor.
sym = scope->get_struct_type()->get_constructor();
} else {
sym = scope->find_symbol(get_simple_name());
}
} else {
sym = scope->find_template(get_simple_name());

View File

@ -20,6 +20,7 @@
#include "cppDeclaration.h"
#include "cppNameComponent.h"
#include "cppFile.h"
#include "cppBisonDefs.h"
#include <string>
#include <vector>
@ -37,6 +38,8 @@ class CPPIdentifier {
public:
CPPIdentifier(const string &name, const CPPFile &file = CPPFile());
CPPIdentifier(const CPPNameComponent &name, const CPPFile &file = CPPFile());
CPPIdentifier(const string &name, const cppyyltype &loc);
CPPIdentifier(const CPPNameComponent &name, const cppyyltype &loc);
void add_name(const string &name);
void add_name(const CPPNameComponent &name);
@ -91,7 +94,7 @@ public:
typedef vector<CPPNameComponent> Names;
Names _names;
CPPScope *_native_scope;
CPPFile _file;
cppyyltype _loc;
};
inline ostream &operator << (ostream &out, const CPPIdentifier &identifier) {

View File

@ -38,7 +38,8 @@ CPPInstance(CPPType *type, const string &name, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(new CPPIdentifier(name)),
_storage_class(storage_class)
_storage_class(storage_class),
_alignment(NULL)
{
_initializer = NULL;
}
@ -53,7 +54,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(ident),
_storage_class(storage_class)
_storage_class(storage_class),
_alignment(NULL)
{
_initializer = NULL;
}
@ -69,7 +71,8 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPInstance::
CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
const CPPFile &file) :
CPPDeclaration(file)
CPPDeclaration(file),
_alignment(NULL)
{
_type = ii->unroll_type(type);
_ident = ii->_ident;
@ -102,7 +105,8 @@ CPPInstance(const CPPInstance &copy) :
_type(copy._type),
_ident(copy._ident),
_initializer(copy._initializer),
_storage_class(copy._storage_class)
_storage_class(copy._storage_class),
_alignment(copy._alignment)
{
assert(_type != NULL);
}
@ -153,6 +157,9 @@ operator == (const CPPInstance &other) const {
if (_storage_class != other._storage_class) {
return false;
}
if (_alignment != other._alignment) {
return false;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
@ -199,6 +206,9 @@ operator < (const CPPInstance &other) const {
if (_storage_class != other._storage_class) {
return _storage_class < other._storage_class;
}
if (_alignment != other._alignment) {
return _alignment < other._alignment;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
@ -252,6 +262,29 @@ set_initializer(CPPExpression *initializer) {
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::set_alignment
// Access: Public
// Description: Sets the number of bytes to align this instance to.
////////////////////////////////////////////////////////////////////
void CPPInstance::
set_alignment(int align) {
_alignment = new CPPExpression(align);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::set_alignment
// Access: Public
// Description: Sets the expression that is used to determine the
// required alignment for the variable. This should
// be a constant expression, but we don't presently
// verify that it is.
////////////////////////////////////////////////////////////////////
void CPPInstance::
set_alignment(CPPExpression *const_expr) {
_alignment = const_expr;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::is_scoped
// Access: Public
@ -536,6 +569,11 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
get_template_scope()->_parameters.write_formal(out, scope);
indent(out, indent_level);
}
if (_alignment != NULL) {
out << "alignas(" << *_alignment << ") ";
}
if (_storage_class & SC_static) {
out << "static ";
}
@ -563,6 +601,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
if (_storage_class & SC_mutable) {
out << "mutable ";
}
if (_storage_class & SC_constexpr) {
out << "constexpr ";
}
string name;
if (_ident != NULL) {

View File

@ -19,7 +19,6 @@
#include "cppDeclaration.h"
#include "cppType.h"
#include "cppIdentifier.h"
#include "cppTemplateParameterList.h"
class CPPInstanceIdentifier;
@ -47,19 +46,20 @@ public:
SC_pure_virtual = 0x0080,
SC_volatile = 0x0100,
SC_mutable = 0x0200,
SC_constexpr = 0x0400,
// This bit is only set by CPPStructType::check_virtual().
SC_inherited_virtual = 0x0400,
SC_inherited_virtual = 0x0800,
// This is a special "storage class" for methods tagged with the
// BLOCKING macro (i.e. the special __blocking keyword). These
// are methods that might block and therefore need to release
// Python threads for their duration.
SC_blocking = 0x0800,
SC_blocking = 0x1000,
// And this is for methods tagged with __extension, which declares
// extension methods defined separately from the source code.
SC_extension = 0x1000,
SC_extension = 0x2000,
};
CPPInstance(CPPType *type, const string &name, int storage_class = 0);
@ -78,6 +78,8 @@ public:
bool operator < (const CPPInstance &other) const;
void set_initializer(CPPExpression *initializer);
void set_alignment(int align);
void set_alignment(CPPExpression *const_expr);
bool is_scoped() const;
CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope,
@ -112,6 +114,7 @@ public:
CPPExpression *_initializer;
int _storage_class;
CPPExpression *_alignment;
private:
typedef map<const CPPTemplateParameterList *, CPPInstance *, CPPTPLCompare> Instantiations;

View File

@ -286,6 +286,11 @@ r_unroll_type(CPPType *start_type,
result = new CPPConstType(r_unroll_type(start_type, mi));
break;
case IIT_volatile:
// Just pass it through for now.
result = r_unroll_type(start_type, mi);
break;
case IIT_paren:
result = r_unroll_type(start_type, mi);
break;

Some files were not shown because too many files have changed in this diff Show More