Initial import
This commit is contained in:
commit
405b86068e
324 changed files with 163599 additions and 0 deletions
17
Nimrod.geany
Executable file
17
Nimrod.geany
Executable file
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name=Nimrod
|
||||||
|
base_path=/media/hda4/nimrod
|
||||||
|
make_in_base_path=false
|
||||||
|
description=
|
||||||
|
run_cmd=python koch.py nim
|
||||||
|
|
||||||
|
[files]
|
||||||
|
current_page=6
|
||||||
|
FILE_NAME_0=786;20;0;16;0;1;0;/media/hda4/nimrod/todo.txt;
|
||||||
|
FILE_NAME_1=7567;34;0;16;0;1;0;/media/hda4/nimrod/lib/base/dialogs.nim;
|
||||||
|
FILE_NAME_2=353;34;0;16;0;1;0;/media/hda4/nimrod/tests/tdialogs.nim;
|
||||||
|
FILE_NAME_3=1811;9;0;16;0;1;0;/media/hda4/nimrod/nim/ccgexprs.pas;
|
||||||
|
FILE_NAME_4=119539;0;0;16;0;1;0;/media/hda4/nimrod/lib/rod_gen/system.c;
|
||||||
|
FILE_NAME_5=192;9;0;16;0;1;0;/media/hda4/nimrod/nim/eval.pas;
|
||||||
|
FILE_NAME_6=0;34;0;16;0;1;0;/media/hda4/nimrod/lib/unicode.nim;
|
||||||
694
cogapp.py
Executable file
694
cogapp.py
Executable file
|
|
@ -0,0 +1,694 @@
|
||||||
|
""" Cog code generation tool.
|
||||||
|
http://nedbatchelder.com/code/cog
|
||||||
|
|
||||||
|
Copyright 2004-2008, Ned Batchelder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# $Id: cogapp.py 141 2008-05-22 10:56:43Z nedbat $
|
||||||
|
|
||||||
|
import md5, os, re, string, sys, traceback, types
|
||||||
|
import imp, compiler
|
||||||
|
import copy, getopt, shlex
|
||||||
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
__all__ = ['Cog', 'CogUsageError']
|
||||||
|
|
||||||
|
__version__ = '2.1.20080522' # History at the end of the file.
|
||||||
|
|
||||||
|
usage = """\
|
||||||
|
cog - generate code with inlined Python code.
|
||||||
|
|
||||||
|
cog [OPTIONS] [INFILE | @FILELIST] ...
|
||||||
|
|
||||||
|
INFILE is the name of an input file.
|
||||||
|
FILELIST is the name of a text file containing file names or
|
||||||
|
other @FILELISTs.
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-c Checksum the output to protect it against accidental change.
|
||||||
|
-d Delete the generator code from the output file.
|
||||||
|
-D name=val Define a global string available to your generator code.
|
||||||
|
-e Warn if a file has no cog code in it.
|
||||||
|
-I PATH Add PATH to the list of directories for data files and modules.
|
||||||
|
-o OUTNAME Write the output to OUTNAME.
|
||||||
|
-r Replace the input file with the output.
|
||||||
|
-s STRING Suffix all generated output lines with STRING.
|
||||||
|
-U Write the output with Unix newlines (only LF line-endings).
|
||||||
|
-w CMD Use CMD if the output file needs to be made writable.
|
||||||
|
A %s in the CMD will be filled with the filename.
|
||||||
|
-x Excise all the generated output without running the generators.
|
||||||
|
-z The [[[end]]] marker can be omitted, and is assumed at eof.
|
||||||
|
-v Print the version of cog and exit.
|
||||||
|
-h Print this help.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get True and False right even if they aren't already defined.
|
||||||
|
True, False = 0==0, 0==1
|
||||||
|
|
||||||
|
# Other package modules
|
||||||
|
from whiteutils import *
|
||||||
|
|
||||||
|
class CogError(Exception):
|
||||||
|
""" Any exception raised by Cog.
|
||||||
|
"""
|
||||||
|
def __init__(self, msg, file='', line=0):
|
||||||
|
if file:
|
||||||
|
Exception.__init__(self, "%s(%d): %s" % (file, line, msg))
|
||||||
|
else:
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
|
||||||
|
class CogUsageError(CogError):
|
||||||
|
""" An error in usage of command-line arguments in cog.
|
||||||
|
"""
|
||||||
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
class CogInternalError(CogError):
|
||||||
|
""" An error in the coding of Cog. Should never happen.
|
||||||
|
"""
|
||||||
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
class CogGeneratedError(CogError):
|
||||||
|
""" An error raised by a user's cog generator.
|
||||||
|
"""
|
||||||
|
pass #pragma: no cover
|
||||||
|
|
||||||
|
class Redirectable:
|
||||||
|
""" An object with its own stdout and stderr files.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.stdout = sys.stdout
|
||||||
|
self.stderr = sys.stderr
|
||||||
|
|
||||||
|
def setOutput(self, stdout=None, stderr=None):
|
||||||
|
""" Assign new files for standard out and/or standard error.
|
||||||
|
"""
|
||||||
|
if stdout:
|
||||||
|
self.stdout = stdout
|
||||||
|
if stderr:
|
||||||
|
self.stderr = stderr
|
||||||
|
|
||||||
|
class CogGenerator(Redirectable):
|
||||||
|
""" A generator pulled from a source file.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
Redirectable.__init__(self)
|
||||||
|
self.markers = []
|
||||||
|
self.lines = []
|
||||||
|
|
||||||
|
def parseMarker(self, l):
|
||||||
|
self.markers.append(l)
|
||||||
|
|
||||||
|
def parseLine(self, l):
|
||||||
|
self.lines.append(l.strip('\n'))
|
||||||
|
|
||||||
|
def getCode(self):
|
||||||
|
""" Extract the executable Python code from the generator.
|
||||||
|
"""
|
||||||
|
# If the markers and lines all have the same prefix
|
||||||
|
# (end-of-line comment chars, for example),
|
||||||
|
# then remove it from all the lines.
|
||||||
|
prefIn = commonPrefix(self.markers + self.lines)
|
||||||
|
if prefIn:
|
||||||
|
self.markers = [ l.replace(prefIn, '', 1) for l in self.markers ]
|
||||||
|
self.lines = [ l.replace(prefIn, '', 1) for l in self.lines ]
|
||||||
|
|
||||||
|
return reindentBlock(self.lines, '')
|
||||||
|
|
||||||
|
def evaluate(self, cog, globals, fname='cog generator'):
|
||||||
|
# figure out the right whitespace prefix for the output
|
||||||
|
prefOut = whitePrefix(self.markers)
|
||||||
|
|
||||||
|
intext = self.getCode()
|
||||||
|
if not intext:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# In Python 2.2, the last line has to end in a newline.
|
||||||
|
intext = "import cog\n" + intext + "\n"
|
||||||
|
code = compiler.compile(intext, filename=str(fname), mode='exec')
|
||||||
|
|
||||||
|
# Make sure the "cog" module has our state.
|
||||||
|
cog.cogmodule.msg = self.msg
|
||||||
|
cog.cogmodule.out = self.out
|
||||||
|
cog.cogmodule.outl = self.outl
|
||||||
|
cog.cogmodule.error = self.error
|
||||||
|
|
||||||
|
self.outstring = ''
|
||||||
|
eval(code, globals)
|
||||||
|
|
||||||
|
# We need to make sure that the last line in the output
|
||||||
|
# ends with a newline, or it will be joined to the
|
||||||
|
# end-output line, ruining cog's idempotency.
|
||||||
|
if self.outstring and self.outstring[-1] != '\n':
|
||||||
|
self.outstring += '\n'
|
||||||
|
|
||||||
|
return reindentBlock(self.outstring, prefOut)
|
||||||
|
|
||||||
|
def msg(self, s):
|
||||||
|
print >>self.stdout, "Message: "+s
|
||||||
|
|
||||||
|
def out(self, sOut='', dedent=False, trimblanklines=False):
|
||||||
|
""" The cog.out function.
|
||||||
|
"""
|
||||||
|
if trimblanklines and ('\n' in sOut):
|
||||||
|
lines = sOut.split('\n')
|
||||||
|
if lines[0].strip() == '':
|
||||||
|
del lines[0]
|
||||||
|
if lines and lines[-1].strip() == '':
|
||||||
|
del lines[-1]
|
||||||
|
sOut = '\n'.join(lines)+'\n'
|
||||||
|
if dedent:
|
||||||
|
sOut = reindentBlock(sOut)
|
||||||
|
self.outstring += sOut
|
||||||
|
|
||||||
|
def outl(self, sOut='', **kw):
|
||||||
|
""" The cog.outl function.
|
||||||
|
"""
|
||||||
|
self.out(sOut, **kw)
|
||||||
|
self.out('\n')
|
||||||
|
|
||||||
|
def error(self, msg='Error raised by cog generator.'):
|
||||||
|
""" The cog.error function.
|
||||||
|
Instead of raising standard python errors, cog generators can use
|
||||||
|
this function. It will display the error without a scary Python
|
||||||
|
traceback.
|
||||||
|
"""
|
||||||
|
raise CogGeneratedError(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class NumberedFileReader:
|
||||||
|
""" A decorator for files that counts the readline()'s called.
|
||||||
|
"""
|
||||||
|
def __init__(self, f):
|
||||||
|
self.f = f
|
||||||
|
self.n = 0
|
||||||
|
|
||||||
|
def readline(self):
|
||||||
|
l = self.f.readline()
|
||||||
|
if l:
|
||||||
|
self.n += 1
|
||||||
|
return l
|
||||||
|
|
||||||
|
def linenumber(self):
|
||||||
|
return self.n
|
||||||
|
|
||||||
|
|
||||||
|
class CogOptions:
|
||||||
|
""" Options for a run of cog.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
# Defaults for argument values.
|
||||||
|
self.args = []
|
||||||
|
self.includePath = []
|
||||||
|
self.defines = {}
|
||||||
|
self.bShowVersion = False
|
||||||
|
self.sMakeWritableCmd = None
|
||||||
|
self.bReplace = False
|
||||||
|
self.bNoGenerate = False
|
||||||
|
self.sOutputName = None
|
||||||
|
self.bWarnEmpty = False
|
||||||
|
self.bHashOutput = False
|
||||||
|
self.bDeleteCode = False
|
||||||
|
self.bEofCanBeEnd = False
|
||||||
|
self.sSuffix = None
|
||||||
|
self.bNewlines = False
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
""" Comparison operator for tests to use.
|
||||||
|
"""
|
||||||
|
return self.__dict__.__cmp__(other.__dict__)
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
""" Make a clone of these options, for further refinement.
|
||||||
|
"""
|
||||||
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
|
def addToIncludePath(self, dirs):
|
||||||
|
""" Add directories to the include path.
|
||||||
|
"""
|
||||||
|
dirs = dirs.split(os.pathsep)
|
||||||
|
self.includePath.extend(dirs)
|
||||||
|
|
||||||
|
def parseArgs(self, argv):
|
||||||
|
# Parse the command line arguments.
|
||||||
|
try:
|
||||||
|
opts, self.args = getopt.getopt(argv, 'cdD:eI:o:rs:Uvw:xz')
|
||||||
|
except getopt.error, msg:
|
||||||
|
raise CogUsageError(msg)
|
||||||
|
|
||||||
|
# Handle the command line arguments.
|
||||||
|
for o, a in opts:
|
||||||
|
if o == '-c':
|
||||||
|
self.bHashOutput = True
|
||||||
|
elif o == '-d':
|
||||||
|
self.bDeleteCode = True
|
||||||
|
elif o == '-D':
|
||||||
|
if a.count('=') < 1:
|
||||||
|
raise CogUsageError("-D takes a name=value argument")
|
||||||
|
name, value = a.split('=', 1)
|
||||||
|
self.defines[name] = value
|
||||||
|
elif o == '-e':
|
||||||
|
self.bWarnEmpty = True
|
||||||
|
elif o == '-I':
|
||||||
|
self.addToIncludePath(a)
|
||||||
|
elif o == '-o':
|
||||||
|
self.sOutputName = a
|
||||||
|
elif o == '-r':
|
||||||
|
self.bReplace = True
|
||||||
|
elif o == '-s':
|
||||||
|
self.sSuffix = a
|
||||||
|
elif o == '-U':
|
||||||
|
self.bNewlines = True
|
||||||
|
elif o == '-v':
|
||||||
|
self.bShowVersion = True
|
||||||
|
elif o == '-w':
|
||||||
|
self.sMakeWritableCmd = a
|
||||||
|
elif o == '-x':
|
||||||
|
self.bNoGenerate = True
|
||||||
|
elif o == '-z':
|
||||||
|
self.bEofCanBeEnd = True
|
||||||
|
else:
|
||||||
|
# Since getopt.getopt is given a list of possible flags,
|
||||||
|
# this is an internal error.
|
||||||
|
raise CogInternalError("Don't understand argument %s" % o)
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
""" Does nothing if everything is OK, raises CogError's if it's not.
|
||||||
|
"""
|
||||||
|
if self.bReplace and self.bDeleteCode:
|
||||||
|
raise CogUsageError("Can't use -d with -r (or you would delete all your source!)")
|
||||||
|
|
||||||
|
if self.bReplace and self.sOutputName:
|
||||||
|
raise CogUsageError("Can't use -o with -r (they are opposites)")
|
||||||
|
|
||||||
|
|
||||||
|
class Cog(Redirectable):
|
||||||
|
""" The Cog engine.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
Redirectable.__init__(self)
|
||||||
|
self.sBeginSpec = '[[[cog'
|
||||||
|
self.sEndSpec = ']]]'
|
||||||
|
self.sEndOutput = '[[[end]]]'
|
||||||
|
self.reEndOutput = re.compile(r'\[\[\[end]]](?P<hashsect> *\(checksum: (?P<hash>[a-f0-9]+)\))')
|
||||||
|
self.sEndFormat = '[[[end]]] (checksum: %s)'
|
||||||
|
|
||||||
|
self.options = CogOptions()
|
||||||
|
self.sOutputMode = 'w'
|
||||||
|
|
||||||
|
self.installCogModule()
|
||||||
|
|
||||||
|
def showWarning(self, msg):
|
||||||
|
print >>self.stdout, "Warning:", msg
|
||||||
|
|
||||||
|
def isBeginSpecLine(self, s):
|
||||||
|
return string.find(s, self.sBeginSpec) >= 0
|
||||||
|
|
||||||
|
def isEndSpecLine(self, s):
|
||||||
|
return string.find(s, self.sEndSpec) >= 0 and \
|
||||||
|
not self.isEndOutputLine(s)
|
||||||
|
|
||||||
|
def isEndOutputLine(self, s):
|
||||||
|
return string.find(s, self.sEndOutput) >= 0
|
||||||
|
|
||||||
|
def installCogModule(self):
|
||||||
|
""" Magic mumbo-jumbo so that imported Python modules
|
||||||
|
can say "import cog" and get our state.
|
||||||
|
"""
|
||||||
|
self.cogmodule = imp.new_module('cog')
|
||||||
|
self.cogmodule.path = []
|
||||||
|
sys.modules['cog'] = self.cogmodule
|
||||||
|
|
||||||
|
def processFile(self, fIn, fOut, fname=None, globals=None):
|
||||||
|
""" Process an input file object to an output file object.
|
||||||
|
fIn and fOut can be file objects, or file names.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sFileIn = fname or ''
|
||||||
|
sFileOut = fname or ''
|
||||||
|
# Convert filenames to files.
|
||||||
|
if isinstance(fIn, types.StringTypes):
|
||||||
|
# Open the input file.
|
||||||
|
sFileIn = fIn
|
||||||
|
fIn = open(fIn, 'r')
|
||||||
|
if isinstance(fOut, types.StringTypes):
|
||||||
|
# Open the output file.
|
||||||
|
sFileOut = fOut
|
||||||
|
fOut = open(fOut, self.sOutputMode)
|
||||||
|
|
||||||
|
fIn = NumberedFileReader(fIn)
|
||||||
|
|
||||||
|
bSawCog = False
|
||||||
|
|
||||||
|
self.cogmodule.inFile = sFileIn
|
||||||
|
self.cogmodule.outFile = sFileOut
|
||||||
|
|
||||||
|
# The globals dict we'll use for this file.
|
||||||
|
if globals is None:
|
||||||
|
globals = {}
|
||||||
|
|
||||||
|
# If there are any global defines, put them in the globals.
|
||||||
|
globals.update(self.options.defines)
|
||||||
|
|
||||||
|
# loop over generator chunks
|
||||||
|
l = fIn.readline()
|
||||||
|
while l:
|
||||||
|
# Find the next spec begin
|
||||||
|
while l and not self.isBeginSpecLine(l):
|
||||||
|
if self.isEndSpecLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sEndSpec,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
if self.isEndOutputLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sEndOutput,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
fOut.write(l)
|
||||||
|
l = fIn.readline()
|
||||||
|
if not l:
|
||||||
|
break
|
||||||
|
if not self.options.bDeleteCode:
|
||||||
|
fOut.write(l)
|
||||||
|
|
||||||
|
# l is the begin spec
|
||||||
|
gen = CogGenerator()
|
||||||
|
gen.setOutput(stdout=self.stdout)
|
||||||
|
gen.parseMarker(l)
|
||||||
|
firstLineNum = fIn.linenumber()
|
||||||
|
self.cogmodule.firstLineNum = firstLineNum
|
||||||
|
|
||||||
|
# If the spec begin is also a spec end, then process the single
|
||||||
|
# line of code inside.
|
||||||
|
if self.isEndSpecLine(l):
|
||||||
|
beg = string.find(l, self.sBeginSpec)
|
||||||
|
end = string.find(l, self.sEndSpec)
|
||||||
|
if beg > end:
|
||||||
|
raise CogError("Cog code markers inverted",
|
||||||
|
file=sFileIn, line=firstLineNum)
|
||||||
|
else:
|
||||||
|
sCode = l[beg+len(self.sBeginSpec):end].strip()
|
||||||
|
gen.parseLine(sCode)
|
||||||
|
else:
|
||||||
|
# Deal with an ordinary code block.
|
||||||
|
l = fIn.readline()
|
||||||
|
|
||||||
|
# Get all the lines in the spec
|
||||||
|
while l and not self.isEndSpecLine(l):
|
||||||
|
if self.isBeginSpecLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sBeginSpec,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
if self.isEndOutputLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sEndOutput,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
if not self.options.bDeleteCode:
|
||||||
|
fOut.write(l)
|
||||||
|
gen.parseLine(l)
|
||||||
|
l = fIn.readline()
|
||||||
|
if not l:
|
||||||
|
raise CogError(
|
||||||
|
"Cog block begun but never ended.",
|
||||||
|
file=sFileIn, line=firstLineNum)
|
||||||
|
|
||||||
|
if not self.options.bDeleteCode:
|
||||||
|
fOut.write(l)
|
||||||
|
gen.parseMarker(l)
|
||||||
|
|
||||||
|
l = fIn.readline()
|
||||||
|
|
||||||
|
# Eat all the lines in the output section. While reading past
|
||||||
|
# them, compute the md5 hash of the old output.
|
||||||
|
hasher = md5.new()
|
||||||
|
while l and not self.isEndOutputLine(l):
|
||||||
|
if self.isBeginSpecLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sBeginSpec,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
if self.isEndSpecLine(l):
|
||||||
|
raise CogError("Unexpected '%s'" % self.sEndSpec,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
hasher.update(l)
|
||||||
|
l = fIn.readline()
|
||||||
|
curHash = hasher.hexdigest()
|
||||||
|
|
||||||
|
if not l and not self.options.bEofCanBeEnd:
|
||||||
|
# We reached end of file before we found the end output line.
|
||||||
|
raise CogError("Missing '%s' before end of file." % self.sEndOutput,
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
|
||||||
|
# Write the output of the spec to be the new output if we're
|
||||||
|
# supposed to generate code.
|
||||||
|
hasher = md5.new()
|
||||||
|
if not self.options.bNoGenerate:
|
||||||
|
sFile = "%s+%d" % (sFileIn, firstLineNum)
|
||||||
|
sGen = gen.evaluate(cog=self, globals=globals, fname=sFile)
|
||||||
|
sGen = self.suffixLines(sGen)
|
||||||
|
hasher.update(sGen)
|
||||||
|
fOut.write(sGen)
|
||||||
|
newHash = hasher.hexdigest()
|
||||||
|
|
||||||
|
bSawCog = True
|
||||||
|
|
||||||
|
# Write the ending output line
|
||||||
|
hashMatch = self.reEndOutput.search(l)
|
||||||
|
if self.options.bHashOutput:
|
||||||
|
if hashMatch:
|
||||||
|
oldHash = hashMatch.groupdict()['hash']
|
||||||
|
if oldHash != curHash:
|
||||||
|
raise CogError("Output has been edited! Delete old checksum to unprotect.",
|
||||||
|
file=sFileIn, line=fIn.linenumber())
|
||||||
|
# Create a new end line with the correct hash.
|
||||||
|
endpieces = l.split(hashMatch.group(0), 1)
|
||||||
|
else:
|
||||||
|
# There was no old hash, but we want a new hash.
|
||||||
|
endpieces = l.split(self.sEndOutput, 1)
|
||||||
|
l = (self.sEndFormat % newHash).join(endpieces)
|
||||||
|
else:
|
||||||
|
# We don't want hashes output, so if there was one, get rid of
|
||||||
|
# it.
|
||||||
|
if hashMatch:
|
||||||
|
l = l.replace(hashMatch.groupdict()['hashsect'], '', 1)
|
||||||
|
|
||||||
|
if not self.options.bDeleteCode:
|
||||||
|
fOut.write(l)
|
||||||
|
l = fIn.readline()
|
||||||
|
|
||||||
|
if not bSawCog and self.options.bWarnEmpty:
|
||||||
|
self.showWarning("no cog code found in %s" % sFileIn)
|
||||||
|
|
||||||
|
# A regex for non-empty lines, used by suffixLines.
|
||||||
|
reNonEmptyLines = re.compile("^\s*\S+.*$", re.MULTILINE)
|
||||||
|
|
||||||
|
def suffixLines(self, text):
|
||||||
|
""" Add suffixes to the lines in text, if our options desire it.
|
||||||
|
text is many lines, as a single string.
|
||||||
|
"""
|
||||||
|
if self.options.sSuffix:
|
||||||
|
# Find all non-blank lines, and add the suffix to the end.
|
||||||
|
repl = r"\g<0>" + self.options.sSuffix.replace('\\', '\\\\')
|
||||||
|
text = self.reNonEmptyLines.sub(repl, text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
def processString(self, sInput, fname=None):
|
||||||
|
""" Process sInput as the text to cog.
|
||||||
|
Return the cogged output as a string.
|
||||||
|
"""
|
||||||
|
fOld = StringIO(sInput)
|
||||||
|
fNew = StringIO()
|
||||||
|
self.processFile(fOld, fNew, fname=fname)
|
||||||
|
return fNew.getvalue()
|
||||||
|
|
||||||
|
def replaceFile(self, sOldPath, sNewText):
|
||||||
|
""" Replace file sOldPath with the contents sNewText
|
||||||
|
"""
|
||||||
|
if not os.access(sOldPath, os.W_OK):
|
||||||
|
# Need to ensure we can write.
|
||||||
|
if self.options.sMakeWritableCmd:
|
||||||
|
# Use an external command to make the file writable.
|
||||||
|
cmd = self.options.sMakeWritableCmd.replace('%s', sOldPath)
|
||||||
|
self.stdout.write(os.popen(cmd).read())
|
||||||
|
if not os.access(sOldPath, os.W_OK):
|
||||||
|
raise CogError("Couldn't make %s writable" % sOldPath)
|
||||||
|
else:
|
||||||
|
# Can't write!
|
||||||
|
raise CogError("Can't overwrite %s" % sOldPath)
|
||||||
|
f = open(sOldPath, self.sOutputMode)
|
||||||
|
f.write(sNewText)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def saveIncludePath(self):
|
||||||
|
self.savedInclude = self.options.includePath[:]
|
||||||
|
self.savedSysPath = sys.path[:]
|
||||||
|
|
||||||
|
def restoreIncludePath(self):
|
||||||
|
self.options.includePath = self.savedInclude
|
||||||
|
self.cogmodule.path = self.options.includePath
|
||||||
|
sys.path = self.savedSysPath
|
||||||
|
|
||||||
|
def addToIncludePath(self, includePath):
|
||||||
|
self.cogmodule.path.extend(includePath)
|
||||||
|
sys.path.extend(includePath)
|
||||||
|
|
||||||
|
def processOneFile(self, sFile):
|
||||||
|
""" Process one filename through cog.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.saveIncludePath()
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.addToIncludePath(self.options.includePath)
|
||||||
|
# Since we know where the input file came from,
|
||||||
|
# push its directory onto the include path.
|
||||||
|
self.addToIncludePath([os.path.dirname(sFile)])
|
||||||
|
|
||||||
|
# Set the file output mode based on whether we want \n or native
|
||||||
|
# line endings.
|
||||||
|
self.sOutputMode = 'w'
|
||||||
|
if self.options.bNewlines:
|
||||||
|
self.sOutputMode = 'wb'
|
||||||
|
|
||||||
|
# How we process the file depends on where the output is going.
|
||||||
|
if self.options.sOutputName:
|
||||||
|
self.processFile(sFile, self.options.sOutputName, sFile)
|
||||||
|
elif self.options.bReplace:
|
||||||
|
# We want to replace the cog file with the output,
|
||||||
|
# but only if they differ.
|
||||||
|
print >>self.stdout, "Cogging %s" % sFile,
|
||||||
|
bNeedNewline = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
fOldFile = open(sFile)
|
||||||
|
sOldText = fOldFile.read()
|
||||||
|
fOldFile.close()
|
||||||
|
sNewText = self.processString(sOldText, fname=sFile)
|
||||||
|
if sOldText != sNewText:
|
||||||
|
print >>self.stdout, " (changed)"
|
||||||
|
bNeedNewline = False
|
||||||
|
self.replaceFile(sFile, sNewText)
|
||||||
|
finally:
|
||||||
|
# The try-finally block is so we can print a partial line
|
||||||
|
# with the name of the file, and print (changed) on the
|
||||||
|
# same line, but also make sure to break the line before
|
||||||
|
# any traceback.
|
||||||
|
if bNeedNewline:
|
||||||
|
print >>self.stdout
|
||||||
|
else:
|
||||||
|
self.processFile(sFile, self.stdout, sFile)
|
||||||
|
finally:
|
||||||
|
self.restoreIncludePath()
|
||||||
|
|
||||||
|
def processFileList(self, sFileList):
|
||||||
|
""" Process the files in a file list.
|
||||||
|
"""
|
||||||
|
for l in open(sFileList).readlines():
|
||||||
|
# Use shlex to parse the line like a shell.
|
||||||
|
lex = shlex.shlex(l, posix=True)
|
||||||
|
lex.whitespace_split = True
|
||||||
|
lex.commenters = '#'
|
||||||
|
# No escapes, so that backslash can be part of the path
|
||||||
|
lex.escape = ''
|
||||||
|
args = list(lex)
|
||||||
|
if args:
|
||||||
|
self.processArguments(args)
|
||||||
|
|
||||||
|
def processArguments(self, args):
|
||||||
|
""" Process one command-line.
|
||||||
|
"""
|
||||||
|
saved_options = self.options
|
||||||
|
self.options = self.options.clone()
|
||||||
|
|
||||||
|
self.options.parseArgs(args[1:])
|
||||||
|
self.options.validate()
|
||||||
|
|
||||||
|
if args[0][0] == '@':
|
||||||
|
if self.options.sOutputName:
|
||||||
|
raise CogUsageError("Can't use -o with @file")
|
||||||
|
self.processFileList(args[0][1:])
|
||||||
|
else:
|
||||||
|
self.processOneFile(args[0])
|
||||||
|
|
||||||
|
self.options = saved_options
|
||||||
|
|
||||||
|
def callableMain(self, argv):
|
||||||
|
""" All of command-line cog, but in a callable form.
|
||||||
|
This is used by main.
|
||||||
|
argv is the equivalent of sys.argv.
|
||||||
|
"""
|
||||||
|
argv0 = argv.pop(0)
|
||||||
|
|
||||||
|
# Provide help if asked for anywhere in the command line.
|
||||||
|
if '-?' in argv or '-h' in argv:
|
||||||
|
print >>self.stderr, usage,
|
||||||
|
return
|
||||||
|
|
||||||
|
self.options.parseArgs(argv)
|
||||||
|
self.options.validate()
|
||||||
|
|
||||||
|
if self.options.bShowVersion:
|
||||||
|
print >>self.stdout, "Cog version %s" % __version__
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.options.args:
|
||||||
|
for a in self.options.args:
|
||||||
|
self.processArguments([a])
|
||||||
|
else:
|
||||||
|
raise CogUsageError("No files to process")
|
||||||
|
|
||||||
|
def main(self, argv):
|
||||||
|
""" Handle the command-line execution for cog.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.callableMain(argv)
|
||||||
|
return 0
|
||||||
|
except CogUsageError, err:
|
||||||
|
print >>self.stderr, err
|
||||||
|
print >>self.stderr, "(for help use -?)"
|
||||||
|
return 2
|
||||||
|
except CogGeneratedError, err:
|
||||||
|
print >>self.stderr, "Error: %s" % err
|
||||||
|
return 3
|
||||||
|
except CogError, err:
|
||||||
|
print >>self.stderr, err
|
||||||
|
return 1
|
||||||
|
except:
|
||||||
|
traceback.print_exc(None, self.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# History:
|
||||||
|
# 20040210: First public version.
|
||||||
|
# 20040220: Text preceding the start and end marker are removed from Python lines.
|
||||||
|
# -v option on the command line shows the version.
|
||||||
|
# 20040311: Make sure the last line of output is properly ended with a newline.
|
||||||
|
# 20040605: Fixed some blank line handling in cog.
|
||||||
|
# Fixed problems with assigning to xml elements in handyxml.
|
||||||
|
# 20040621: Changed all line-ends to LF from CRLF.
|
||||||
|
# 20041002: Refactor some option handling to simplify unittesting the options.
|
||||||
|
# 20041118: cog.out and cog.outl have optional string arguments.
|
||||||
|
# 20041119: File names weren't being properly passed around for warnings, etc.
|
||||||
|
# 20041122: Added cog.firstLineNum: a property with the line number of the [[[cog line.
|
||||||
|
# Added cog.inFile and cog.outFile: the names of the input and output file.
|
||||||
|
# 20041218: Single-line cog generators, with start marker and end marker on
|
||||||
|
# the same line.
|
||||||
|
# 20041230: Keep a single globals dict for all the code fragments in a single
|
||||||
|
# file so they can share state.
|
||||||
|
# 20050206: Added the -x switch to remove all generated output.
|
||||||
|
# 20050218: Now code can be on the marker lines as well.
|
||||||
|
# 20050219: Added -c switch to checksum the output so that edits can be
|
||||||
|
# detected before they are obliterated.
|
||||||
|
# 20050521: Added cog.error, contributed by Alexander Belchenko.
|
||||||
|
# 20050720: Added code deletion and settable globals contributed by Blake Winton.
|
||||||
|
# 20050724: Many tweaks to improve code coverage.
|
||||||
|
# 20050726: Error messages are now printed with no traceback.
|
||||||
|
# Code can no longer appear on the marker lines,
|
||||||
|
# except for single-line style.
|
||||||
|
# -z allows omission of the [[[end]]] marker, and it will be assumed
|
||||||
|
# at the end of the file.
|
||||||
|
# 20050729: Refactor option parsing into a separate class, in preparation for
|
||||||
|
# future features.
|
||||||
|
# 20050805: The cogmodule.path wasn't being properly maintained.
|
||||||
|
# 20050808: Added the -D option to define a global value.
|
||||||
|
# 20050810: The %s in the -w command is dealt with more robustly.
|
||||||
|
# Added the -s option to suffix output lines with a marker.
|
||||||
|
# 20050817: Now @files can have arguments on each line to change the cog's
|
||||||
|
# behavior for that line.
|
||||||
|
# 20051006: Version 2.0
|
||||||
|
# 20080521: -U options lets you create Unix newlines on Windows. Thanks,
|
||||||
|
# Alexander Belchenko.
|
||||||
|
# 20080522: It's now ok to have -d with output to stdout, and now we validate
|
||||||
|
# the args after each line of an @file.
|
||||||
288
config/doctempl.cfg
Executable file
288
config/doctempl.cfg
Executable file
|
|
@ -0,0 +1,288 @@
|
||||||
|
# This is the config file for the documentation generator.
|
||||||
|
# (c) 2008 Andreas Rumpf
|
||||||
|
# Feel free to edit the templates as you need.
|
||||||
|
|
||||||
|
doc.section = """
|
||||||
|
<div class="section" id="$sectionID">
|
||||||
|
<h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>
|
||||||
|
<dl class="item">
|
||||||
|
$content
|
||||||
|
</dl></div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.section.toc = """
|
||||||
|
<li>
|
||||||
|
<a class="reference" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
|
||||||
|
<ul class="simple">
|
||||||
|
$content
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.item = """
|
||||||
|
<dt id="$itemID"><pre>$header</pre></dt>
|
||||||
|
<dd>
|
||||||
|
$desc
|
||||||
|
</dd>
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.item.toc = """
|
||||||
|
<li><a class="reference" href="#$itemID">$name</a></li>
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.toc = """
|
||||||
|
<div class="navigation">
|
||||||
|
<p class="topic-title first">Navigation</p>
|
||||||
|
<ul class="simple">
|
||||||
|
$content
|
||||||
|
</ul>
|
||||||
|
</div>"""
|
||||||
|
|
||||||
|
doc.body_toc = """
|
||||||
|
$tableofcontents
|
||||||
|
<div class="content">
|
||||||
|
$moduledesc
|
||||||
|
$content
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.body_no_toc = """
|
||||||
|
$moduledesc
|
||||||
|
$content
|
||||||
|
"""
|
||||||
|
|
||||||
|
doc.file = """<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<!-- This file is generated by Nimrod. -->
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>$title</title>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
span.DecNumber {color: blue}
|
||||||
|
span.BinNumber {color: blue}
|
||||||
|
span.HexNumber {color: blue}
|
||||||
|
span.OctNumber {color: blue}
|
||||||
|
span.FloatNumber {color: blue}
|
||||||
|
span.Identifier {color: black}
|
||||||
|
span.Keyword {font-weight: bold}
|
||||||
|
span.StringLit {color: blue}
|
||||||
|
span.LongStringLit {color: blue}
|
||||||
|
span.CharLit {color: blue}
|
||||||
|
span.EscapeSequence {color: black}
|
||||||
|
span.Operator {color: black}
|
||||||
|
span.Punctation {color: black}
|
||||||
|
span.Comment, span.LongComment {font-style:italic; color: green}
|
||||||
|
span.RegularExpression {color: pink}
|
||||||
|
span.TagStart {color: yellow}
|
||||||
|
span.TagEnd {color: yellow}
|
||||||
|
span.Key {color: blue}
|
||||||
|
span.Value {color: black}
|
||||||
|
span.RawData {color: blue}
|
||||||
|
span.Assembler {color: blue}
|
||||||
|
span.Preprocessor {color: yellow}
|
||||||
|
span.Directive {color: yellow}
|
||||||
|
span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
|
||||||
|
span.Other {color: black}
|
||||||
|
|
||||||
|
div.navigation {
|
||||||
|
float: left; width: 20em;
|
||||||
|
margin: 0; padding: 0; /*
|
||||||
|
border: 1px dashed gold; */
|
||||||
|
outline: 3px outset #99ff99; //gold;
|
||||||
|
background-color: #99ff99;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navigation ul {list-style-type: none;}
|
||||||
|
div.navigation ul li a, div.navigation ul li a:visited {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #CC0000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
div.navigation ul li a:hover {
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 2px outset gold;
|
||||||
|
background-color: gold; /* #779977;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
div.content {
|
||||||
|
margin-left: 20em;
|
||||||
|
padding: 0 1em;
|
||||||
|
border: 1px dashed gold;
|
||||||
|
min-width: 16em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.item dd, dl.item dd p {
|
||||||
|
margin-top:3px;
|
||||||
|
}
|
||||||
|
dl.item dd pre {
|
||||||
|
margin-left: 15pt;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
dl.item dt, dl.item dt pre {
|
||||||
|
margin: 20pt 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre, span.tok {
|
||||||
|
background-color:#F9F9F9;
|
||||||
|
border:1px dotted #2F6FAB;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
:Author: David Goodger
|
||||||
|
:Contact: goodger@python.org
|
||||||
|
:Date: Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006)
|
||||||
|
:Revision: Revision: 4564
|
||||||
|
:Copyright: This stylesheet has been placed in the public domain.
|
||||||
|
|
||||||
|
Default cascading style sheet for the HTML output of Docutils.
|
||||||
|
|
||||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||||
|
customize this style sheet.
|
||||||
|
*/
|
||||||
|
/* used to remove borders from tables and images */
|
||||||
|
.borderless, table.borderless td, table.borderless th { border: 0 }
|
||||||
|
|
||||||
|
table.borderless td, table.borderless th {
|
||||||
|
/* Override padding for "table.docutils td" with "! important".
|
||||||
|
The right padding separates the table cells. */
|
||||||
|
padding: 0 0.5em 0 0 ! important }
|
||||||
|
|
||||||
|
.first { margin-top: 0 ! important }
|
||||||
|
.last, .with-subtitle { margin-bottom: 0 ! important }
|
||||||
|
.hidden { display: none }
|
||||||
|
a.toc-backref { text-decoration: none ; color: black }
|
||||||
|
blockquote.epigraph { margin: 2em 5em ; }
|
||||||
|
dl.docutils dd { margin-bottom: 0.5em }
|
||||||
|
div.abstract { margin: 2em 5em }
|
||||||
|
div.abstract p.topic-title { font-weight: bold ; text-align: center }
|
||||||
|
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||||
|
div.hint, div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ; border: medium outset ; padding: 1em }
|
||||||
|
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||||
|
div.important p.admonition-title, div.note p.admonition-title,
|
||||||
|
div.tip p.admonition-title { font-weight: bold ; font-family: sans-serif }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title { color: red ; font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||||
|
compound paragraphs.
|
||||||
|
div.compound .compound-first, div.compound .compound-middle {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.compound .compound-last, div.compound .compound-middle {
|
||||||
|
margin-top: 0.5em }
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.dedication { margin: 2em 5em ; text-align: center ; font-style: italic }
|
||||||
|
div.dedication p.topic-title { font-weight: bold ; font-style: normal }
|
||||||
|
div.figure { margin-left: 2em ; margin-right: 2em }
|
||||||
|
div.footer, div.header { clear: both; font-size: smaller }
|
||||||
|
div.line-block { display: block ; margin-top: 1em ; margin-bottom: 1em }
|
||||||
|
div.line-block div.line-block { margin-top: 0 ; margin-bottom: 0 ;
|
||||||
|
margin-left: 1.5em }
|
||||||
|
div.sidebar { margin-left: 1em ; border: medium outset ;
|
||||||
|
padding: 1em ; background-color: #ffffee ; width: 40% ; float: right ;
|
||||||
|
clear: right }
|
||||||
|
|
||||||
|
div.sidebar p.rubric { font-family: sans-serif ; font-size: medium }
|
||||||
|
div.system-messages { margin: 5em }
|
||||||
|
div.system-messages h1 { color: red }
|
||||||
|
div.system-message { border: medium outset ; padding: 1em }
|
||||||
|
div.system-message p.system-message-title { color: red ; font-weight: bold }
|
||||||
|
div.topic { margin: 2em;}
|
||||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||||
|
margin-top: 0.4em }
|
||||||
|
h1.title { text-align: center }
|
||||||
|
h2.subtitle { text-align: center }
|
||||||
|
hr.docutils { width: 75% }
|
||||||
|
img.align-left { clear: left }
|
||||||
|
img.align-right { clear: right }
|
||||||
|
ol.simple, ul.simple { margin-bottom: 1em }
|
||||||
|
ol.arabic { list-style: decimal }
|
||||||
|
ol.loweralpha { list-style: lower-alpha }
|
||||||
|
ol.upperalpha { list-style: upper-alpha }
|
||||||
|
ol.lowerroman { list-style: lower-roman }
|
||||||
|
ol.upperroman { list-style: upper-roman }
|
||||||
|
p.attribution { text-align: right ; margin-left: 50% }
|
||||||
|
p.caption { font-style: italic }
|
||||||
|
p.credits { font-style: italic ; font-size: smaller }
|
||||||
|
p.label { white-space: nowrap }
|
||||||
|
p.rubric { font-weight:bold;font-size:larger;color:maroon;text-align:center}
|
||||||
|
p.sidebar-title {font-family: sans-serif ;font-weight: bold ;font-size: larger }
|
||||||
|
p.sidebar-subtitle {font-family: sans-serif ; font-weight: bold }
|
||||||
|
p.topic-title { font-weight: bold }
|
||||||
|
pre.address { margin-bottom: 0;margin-top:0;font-family:serif;font-size:100% }
|
||||||
|
pre.literal-block, pre.doctest-block {margin-left: 2em ;margin-right: 2em }
|
||||||
|
span.classifier {font-family: sans-serif;font-style: oblique }
|
||||||
|
span.classifier-delimiter {font-family: sans-serif;font-weight: bold }
|
||||||
|
span.interpreted {font-family: sans-serif }
|
||||||
|
span.option {white-space: nowrap }
|
||||||
|
span.pre {white-space: pre }
|
||||||
|
span.problematic {color: red }
|
||||||
|
span.section-subtitle {
|
||||||
|
/* font-size relative to parent (h1..h6 element) */
|
||||||
|
font-size: 80% }
|
||||||
|
|
||||||
|
table.citation { border-left: solid 1px gray; margin-left: 1px }
|
||||||
|
table.docinfo {margin: 2em 4em }
|
||||||
|
table.docutils {margin-top: 0.5em;margin-bottom: 0.5em }
|
||||||
|
table.footnote {border-left: solid 1px black;margin-left: 1px }
|
||||||
|
|
||||||
|
table.docutils td, table.docutils th,
|
||||||
|
table.docinfo td, table.docinfo th {padding-left: 0.5em;padding-right: 0.5em;
|
||||||
|
vertical-align: top}
|
||||||
|
|
||||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||||
|
font-weight: bold;text-align: left;white-space: nowrap;padding-left: 0 }
|
||||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {font-size: 100% }
|
||||||
|
ul.auto-toc { list-style-type: none }
|
||||||
|
/*a.reference { color: #E00000; font-weight:bold;}
|
||||||
|
a.reference:hover {color: #E00000;background-color: #ffff00;display: margin;
|
||||||
|
font-weight:bold;}*/
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
function toggleElem(id) {
|
||||||
|
var e = document.getElementById(id);
|
||||||
|
e.style.display = e.style.display == 'none' ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
var gOpen = 'none'
|
||||||
|
function toggleAll() {
|
||||||
|
gOpen = gOpen == 'none' ? 'block' : 'none';
|
||||||
|
var i = 1
|
||||||
|
while (1) {
|
||||||
|
var e = document.getElementById("m"+i)
|
||||||
|
if (!e) break;
|
||||||
|
e.style.display = gOpen
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
document.getElementById('toggleButton').value =
|
||||||
|
gOpen == 'none' ? 'Show Details' : 'Hide Details';
|
||||||
|
}
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="documentId">
|
||||||
|
<h1 class="title">$title</h1>
|
||||||
|
$content
|
||||||
|
<small>Generated: $date $time UTC</small>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@write "used doctempl.cfg"
|
||||||
150
config/nimrod.cfg
Executable file
150
config/nimrod.cfg
Executable file
|
|
@ -0,0 +1,150 @@
|
||||||
|
# Configuration file for the Nimrod Compiler.
|
||||||
|
# Generated by the koch.py script.
|
||||||
|
# (c) 2008 Andreas Rumpf
|
||||||
|
|
||||||
|
# Feel free to edit the default values as you need.
|
||||||
|
|
||||||
|
# You may set environment variables with
|
||||||
|
# @putenv "key" "val"
|
||||||
|
# Environment variables cannot be used in the options, however!
|
||||||
|
|
||||||
|
# Just call the compiler with several options:
|
||||||
|
cc = @if unix: gcc @else: bcc @end
|
||||||
|
lib="$nimrod/lib"
|
||||||
|
path="$lib/base"
|
||||||
|
path="$lib/base/gtk"
|
||||||
|
path="$lib/base/cairo"
|
||||||
|
path="$lib/base/x11"
|
||||||
|
path="$lib/windows"
|
||||||
|
path="$lib/posix"
|
||||||
|
path="$lib/extra"
|
||||||
|
|
||||||
|
# additional defines:
|
||||||
|
#define=""
|
||||||
|
# additional options always passed to the compiler:
|
||||||
|
c_file_cache=on
|
||||||
|
line_dir=off
|
||||||
|
|
||||||
|
hint[LineTooLong]=off
|
||||||
|
hint[XDeclaredButNotUsed]=off
|
||||||
|
|
||||||
|
@if unix:
|
||||||
|
passl= "-ldl"
|
||||||
|
path = "$lib/base/gtk"
|
||||||
|
@end
|
||||||
|
|
||||||
|
@if icc:
|
||||||
|
passl = "-cxxlib"
|
||||||
|
passc = "-cxxlib"
|
||||||
|
@end
|
||||||
|
|
||||||
|
# Configuration for the Borland C++ Compiler:
|
||||||
|
@if windows:
|
||||||
|
bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
|
||||||
|
@end
|
||||||
|
bcc.options.debug = ""
|
||||||
|
# turn off warnings about unreachable code and inline procs:
|
||||||
|
bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
|
||||||
|
bcc.options.speed = "-O2 -6"
|
||||||
|
bcc.options.size = "-O1 -6"
|
||||||
|
|
||||||
|
# Configuration for the Visual C/C++ compiler:
|
||||||
|
@if vcc:
|
||||||
|
@prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
|
||||||
|
@prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
|
||||||
|
@prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
|
||||||
|
#~ @prepend_env VSINSTALLDIR C:\eigenes\compiler\vcc2005
|
||||||
|
#~ @prepend_env VCINSTALLDIR C:\eigenes\compiler\vcc2005\VC
|
||||||
|
#~ @prepend_env FrameworkDir C:\WINDOWS\Microsoft.NET\Framework
|
||||||
|
#~ @prepend_env FrameworkVersion v2.0.50727
|
||||||
|
#~ @prepend_env FrameworkSDKDir C:\eigenes\compiler\vcc2005\SDK\v2.0
|
||||||
|
#~ @set DevEnvDir=C:\eigenes\compiler\vcc2005\Common7\IDE
|
||||||
|
#~ @prepend_env PATH %DevEnvDir%;%VCINSTALLDIR%\BIN;%VSINSTALLDIR%\Common7\Tools;%VSINSTALLDIR%\Common7\Tools\bin;%VCINSTALLDIR%\PlatformSDK\bin;%FrameworkSDKDir%\bin;%FrameworkDir%\%FrameworkVersion%;%VCINSTALLDIR%\VCPackages;%PATH%
|
||||||
|
#~ @prepend_env INCLUDE %VCINSTALLDIR%\ATLMFC\INCLUDE;%VCINSTALLDIR%\INCLUDE;%VCINSTALLDIR%\PlatformSDK\include;%FrameworkSDKDir%\include;%INCLUDE%
|
||||||
|
#~ @prepend_env LIB %VCINSTALLDIR%\ATLMFC\LIB;%VCINSTALLDIR%\LIB;%VCINSTALLDIR%\PlatformSDK\lib;%FrameworkSDKDir%\lib;%LIB%
|
||||||
|
#~ @prepend_env LIBPATH %FrameworkDir%\%FrameworkVersion%;%VCINSTALLDIR%\ATLMFC\LIB
|
||||||
|
@end
|
||||||
|
@if windows:
|
||||||
|
vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
|
||||||
|
@end
|
||||||
|
vcc.options.debug = "/GZ /ZI"
|
||||||
|
vcc.options.always = "/nologo"
|
||||||
|
vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
|
||||||
|
vcc.options.size = "/O1 /G7"
|
||||||
|
|
||||||
|
# Configuration for the Watcom C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
wcc.path = r"C:\eigenes\compiler\watcom\binnt"
|
||||||
|
@end
|
||||||
|
wcc.options.debug = "-d2"
|
||||||
|
wcc.options.always = "-6 -zw -w-"
|
||||||
|
wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
|
||||||
|
wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
|
||||||
|
|
||||||
|
# Configuration for the GNU C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
gcc.path = r"C:\eigenes\compiler\mingw\bin"
|
||||||
|
@end
|
||||||
|
gcc.options.debug = "-g"
|
||||||
|
@if macosx:
|
||||||
|
gcc.options.always = "-Wall -g -fasm-blocks"
|
||||||
|
@else:
|
||||||
|
gcc.options.always = "-Wall -g"
|
||||||
|
@end
|
||||||
|
gcc.options.speed = "-O3 -ffast-math"
|
||||||
|
gcc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
# Configuration for the Digital Mars C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
|
||||||
|
@end
|
||||||
|
dmc.options.debug = "-g"
|
||||||
|
dmc.options.always = "-Jm"
|
||||||
|
dmc.options.speed = "-ff -o -6"
|
||||||
|
dmc.options.size = "-ff -o -6"
|
||||||
|
|
||||||
|
# Configuration for the LCC compiler:
|
||||||
|
@if windows:
|
||||||
|
lcc.path = r"C:\eigenes\compiler\lcc\bin"
|
||||||
|
@end
|
||||||
|
lcc.options.debug = "-g5"
|
||||||
|
lcc.options.always = "-e1"
|
||||||
|
lcc.options.speed = "-O -p6"
|
||||||
|
lcc.options.size = "-O -p6"
|
||||||
|
|
||||||
|
# Configuration for the Tiny C Compiler:
|
||||||
|
@if windows:
|
||||||
|
tcc.path = r"C:\eigenes\compiler\tcc\bin"
|
||||||
|
@end
|
||||||
|
tcc.options.debug = "-b"
|
||||||
|
tcc.options.always = ""
|
||||||
|
tcc.options.speed = ""
|
||||||
|
tcc.options.size = ""
|
||||||
|
|
||||||
|
# Configuration for the Pelles C compiler:
|
||||||
|
@if windows:
|
||||||
|
pcc.path = r"C:\eigenes\compiler\pellesc\bin"
|
||||||
|
@end
|
||||||
|
pcc.options.debug = "-Zi"
|
||||||
|
pcc.options.always = "-Ze"
|
||||||
|
pcc.options.speed = "-Ox"
|
||||||
|
pcc.options.size = "-Os"
|
||||||
|
|
||||||
|
# Configuration for the LLVM GCC compiler:
|
||||||
|
@if windows:
|
||||||
|
llvm_gcc.path = r"c:\eignes\compiler\llvm-gcc\bin"
|
||||||
|
@end
|
||||||
|
llvm_gcc.options.debug = "-g"
|
||||||
|
llvm_gcc.options.always = "-w"
|
||||||
|
llvm_gcc.options.speed = "-O3 -ffast-math"
|
||||||
|
llvm_gcc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
@if windows:
|
||||||
|
icc.path = r"c:\eignes\compiler\icc\bin"
|
||||||
|
@end
|
||||||
|
icc.options.debug = "-g"
|
||||||
|
icc.options.always = "-w"
|
||||||
|
icc.options.speed = "-O3 -ffast-math"
|
||||||
|
icc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
@write "used default config file"
|
||||||
5
configure
vendored
Executable file
5
configure
vendored
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#! /usr/bin/env sh
|
||||||
|
|
||||||
|
python koch.py $@ configure
|
||||||
|
|
||||||
|
|
||||||
43
data/advopt.txt
Executable file
43
data/advopt.txt
Executable file
|
|
@ -0,0 +1,43 @@
|
||||||
|
Advanced commands::
|
||||||
|
pas convert a Pascal file to Nimrod standard syntax
|
||||||
|
pretty pretty print the inputfile
|
||||||
|
gen_depend generate a DOT file containing the
|
||||||
|
module dependency graph
|
||||||
|
list_def list all defined conditionals and exit
|
||||||
|
rst2html converts a reStructuredText file to HTML
|
||||||
|
check checks the project for syntax and semantic
|
||||||
|
parse parses a single file (for debugging Nimrod)
|
||||||
|
scan tokenizes a single file (for debugging Nimrod)
|
||||||
|
debugtrans for debugging the transformation pass
|
||||||
|
Advanced options:
|
||||||
|
-w, --warnings:on|off warnings ON|OFF
|
||||||
|
--warning[X]:on|off specific warning X ON|OFF
|
||||||
|
--hints:on|off hints ON|OFF
|
||||||
|
--hint[X]:on|off specific hint X ON|OFF
|
||||||
|
--cc:C_COMPILER set the C/C++ compiler to use
|
||||||
|
--lib:PATH set the system library path
|
||||||
|
-c, --compile_only compile only; do not assemble or link
|
||||||
|
--no_linking compile but do not link
|
||||||
|
--gen_script generate a compile script (in the 'rod_gen'
|
||||||
|
subdirectory named 'compile_$project$scriptext')
|
||||||
|
--os:SYMBOL set the target operating system (cross-compilation)
|
||||||
|
--cpu:SYMBOL set the target processor (cross-compilation)
|
||||||
|
--debuginfo enables debug information
|
||||||
|
-t, --passc:OPTION pass an option to the C compiler
|
||||||
|
-l, --passl:OPTION pass an option to the linker
|
||||||
|
--gen_mapping generate a mapping file containing
|
||||||
|
(Nimrod, mangled) identifier pairs
|
||||||
|
--merge_output generate only one C output file
|
||||||
|
--line_dir:on|off generation of #line directive ON|OFF
|
||||||
|
--checkpoints:on|off turn on|off checkpoints; for debugging Nimrod
|
||||||
|
--skip_cfg do not read the general configuration file
|
||||||
|
--skip_proj_cfg do not read the project's configuration file
|
||||||
|
--import:MODULE_FILE import the given module implicitly for each module
|
||||||
|
--maxerr:NUMBER stop compilation after NUMBER errors; broken!
|
||||||
|
--ast_cache:on|off caching of ASTs ON|OFF (default: OFF)
|
||||||
|
--c_file_cache:on|off caching of generated C files ON|OFF (default: OFF)
|
||||||
|
--index:FILE use FILE to generate a documenation index file
|
||||||
|
--putenv:key=value set an environment variable
|
||||||
|
--list_cmd list the commands used to execute external programs
|
||||||
|
-v, --verbose show what Nimrod is doing
|
||||||
|
--version show detailed version information
|
||||||
258
data/ast.yml
Executable file
258
data/ast.yml
Executable file
|
|
@ -0,0 +1,258 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nimrod Compiler
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
{
|
||||||
|
'SymFlag': [ # already 32 flags!
|
||||||
|
'sfGeneric', # whether an operator, proc or type is generic
|
||||||
|
'sfForward', # symbol is forward directed
|
||||||
|
'sfImportc', # symbol is external; imported
|
||||||
|
'sfExportc', # symbol is exported (under a specified name)
|
||||||
|
'sfVolatile', # variable is volatile
|
||||||
|
'sfUsed', # read access of sym (for warnings) or simply used
|
||||||
|
'sfWrite', # write access of variable (for hints)
|
||||||
|
'sfRegister', # variable should be placed in a register
|
||||||
|
'sfPure', # object is "pure" that means it has no type-information
|
||||||
|
'sfCodeGenerated', # wether we have already code generated for the proc
|
||||||
|
'sfPrivate', # symbol should be made private after module compilation
|
||||||
|
'sfGlobal', # symbol is at global scope
|
||||||
|
'sfResult', # variable is 'result' in proc
|
||||||
|
'sfNoSideEffect', # proc has no side effects
|
||||||
|
'sfMainModule', # module is the main module
|
||||||
|
'sfSystemModule', # module is the system module
|
||||||
|
'sfNoReturn', # proc never returns (an exit proc)
|
||||||
|
'sfReturnsNew', # proc returns new allocated thing (allows optimizations)
|
||||||
|
'sfInInterface', # symbol is in interface section declared
|
||||||
|
'sfNoStatic', # symbol is used within an iterator (needed for codegen)
|
||||||
|
# so it cannot be 'static' in the C code
|
||||||
|
# this is called 'nostatic' in the pragma section
|
||||||
|
'sfCompilerProc', # proc is a compiler proc, that is a C proc that is
|
||||||
|
# needed for the code generator
|
||||||
|
'sfCppMethod', # proc is a C++ method
|
||||||
|
'sfDiscriminant', # field is a discriminant in a record/object
|
||||||
|
'sfDeprecated', # symbol is deprecated
|
||||||
|
'sfInClosure', # variable is accessed by a closure
|
||||||
|
'sfIsCopy', # symbol is a copy; needed for proper name mangling
|
||||||
|
'sfStar', # symbol has * visibility
|
||||||
|
'sfMinus' # symbol has - visibility
|
||||||
|
],
|
||||||
|
|
||||||
|
'TypeFlag': [
|
||||||
|
'tfIsDistinct', # better use this flag to make it easier for accessing
|
||||||
|
# typeKind in the code generators
|
||||||
|
'tfGeneric', # type is a generic one
|
||||||
|
'tfExternal', # type is external
|
||||||
|
'tfImported', # type is imported from C
|
||||||
|
'tfInfoGenerated', # whether we have generated type information for this type
|
||||||
|
'tfSemChecked', # used to mark types that's semantic has been checked;
|
||||||
|
# used to prevend endless loops during semantic checking
|
||||||
|
'tfHasOutParams', # for a proc or iterator p:
|
||||||
|
# it indicates that p has out or in out parameters: this
|
||||||
|
# is used to speed up semantic checking a bit
|
||||||
|
'tfEnumHasWholes', # enum cannot be mapped into a range
|
||||||
|
'tfVarargs', # procedure has C styled varargs
|
||||||
|
'tfAssignable' # can the type be assigned to?
|
||||||
|
],
|
||||||
|
|
||||||
|
'TypeKind': [ # order is important!
|
||||||
|
# Don't forget to change hti.nim if you make a change here
|
||||||
|
'tyNone', 'tyBool', 'tyChar',
|
||||||
|
'tyEmptySet', 'tyArrayConstr', 'tyNil', 'tyRecordConstr',
|
||||||
|
'tyGeneric',
|
||||||
|
'tyGenericInst', # instantiated generic type
|
||||||
|
'tyGenericParam',
|
||||||
|
'tyEnum', 'tyAnyEnum',
|
||||||
|
'tyArray',
|
||||||
|
'tyRecord',
|
||||||
|
'tyObject',
|
||||||
|
'tyTuple',
|
||||||
|
'tySet',
|
||||||
|
'tyRange',
|
||||||
|
'tyPtr', 'tyRef',
|
||||||
|
'tyVar',
|
||||||
|
'tySequence',
|
||||||
|
'tyProc',
|
||||||
|
'tyPointer', 'tyOpenArray',
|
||||||
|
'tyString', 'tyCString', 'tyForward',
|
||||||
|
# numerical types:
|
||||||
|
'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 'tyInt64', # signed integers
|
||||||
|
'tyFloat', 'tyFloat32', 'tyFloat64', 'tyFloat128'
|
||||||
|
],
|
||||||
|
|
||||||
|
'NodeKind': [ # these are pure nodes
|
||||||
|
# order is extremely important, because ranges are used to check whether
|
||||||
|
# a node belongs to a certain class
|
||||||
|
'nkNone', # unknown node kind: indicates an error
|
||||||
|
|
||||||
|
# Expressions:
|
||||||
|
# Atoms:
|
||||||
|
'nkEmpty', # the node is empty
|
||||||
|
'nkIdent', # node is an identifier
|
||||||
|
'nkSym', # node is a symbol
|
||||||
|
'nkType', # node is used for its typ field
|
||||||
|
|
||||||
|
'nkCharLit', # a character literal ''
|
||||||
|
'nkRCharLit', # a raw character literal r''
|
||||||
|
|
||||||
|
'nkIntLit', # an integer literal
|
||||||
|
'nkInt8Lit',
|
||||||
|
'nkInt16Lit',
|
||||||
|
'nkInt32Lit',
|
||||||
|
'nkInt64Lit',
|
||||||
|
'nkFloatLit', # a floating point literal
|
||||||
|
'nkFloat32Lit',
|
||||||
|
'nkFloat64Lit',
|
||||||
|
'nkStrLit', # a string literal ""
|
||||||
|
'nkRStrLit', # a raw string literal r""
|
||||||
|
'nkTripleStrLit', # a triple string literal """
|
||||||
|
'nkNilLit', # the nil literal
|
||||||
|
# end of atoms
|
||||||
|
'nkDotCall', # used to temporarily flag a nkCall node; this is used
|
||||||
|
# for transforming ``s.len`` to ``len(s)``
|
||||||
|
'nkCommand', # a call like ``p 2 4`` without parenthesis
|
||||||
|
'nkCall', # a call like p(x, y) or an operation like +(a, b)
|
||||||
|
'nkGenericCall', # a call with given type parameters
|
||||||
|
'nkExplicitTypeListCall', # a call with given explicit typelist
|
||||||
|
'nkExprEqExpr', # a named parameter with equals: ''expr = expr''
|
||||||
|
'nkExprColonExpr', # a named parameter with colon: ''expr: expr''
|
||||||
|
'nkIdentDefs', # a definition like `a, b: typeDesc = expr`
|
||||||
|
# either typeDesc or expr may be nil; used in
|
||||||
|
# formal parameters, var statements, etc.
|
||||||
|
'nkInfix', # a call like (a + b)
|
||||||
|
'nkPrefix', # a call like !a
|
||||||
|
'nkPostfix', # something like a! (also used for visibility)
|
||||||
|
'nkPar', # syntactic ()
|
||||||
|
'nkCurly', # syntactic {}
|
||||||
|
'nkBracket', # syntactic []
|
||||||
|
'nkBracketExpr', # an expression like a[i..j, k]
|
||||||
|
'nkPragmaExpr', # an expression like a{.pragmas.}
|
||||||
|
'nkRange', # an expression like i..j
|
||||||
|
'nkDotExpr', # a.b
|
||||||
|
'nkCheckedFieldExpr', # a.b, but b is a field that needs to be checked
|
||||||
|
'nkDerefExpr', # a^
|
||||||
|
'nkIfExpr', # if as an expression
|
||||||
|
'nkElifExpr',
|
||||||
|
'nkElseExpr',
|
||||||
|
'nkLambda', # lambda expression
|
||||||
|
'nkAccQuoted', # `a` as a node
|
||||||
|
'nkHeaderQuoted', # `a(x: int)` as a node
|
||||||
|
|
||||||
|
'nkSetConstr', # a set constructor {}
|
||||||
|
'nkConstSetConstr', # a set constructor with only constant expressions
|
||||||
|
'nkArrayConstr', # an array constructor []
|
||||||
|
'nkConstArrayConstr', # an array constructor with only constant expressions
|
||||||
|
'nkRecordConstr', # a record constructor []
|
||||||
|
'nkConstRecordConstr', # a record constructor with only constant expressions
|
||||||
|
'nkTableConstr', # a table constructor {expr: expr}
|
||||||
|
'nkConstTableConstr', # a table constructor with only constant expressions
|
||||||
|
'nkQualified', # describes a.b for qualified identifiers
|
||||||
|
'nkHiddenStdConv', # an implicit standard type conversion
|
||||||
|
'nkHiddenSubConv', # an implicit type conversion from a subtype
|
||||||
|
# to a supertype
|
||||||
|
'nkHiddenCallConv', # an implicit type conversion via a type converter
|
||||||
|
'nkConv', # a type conversion
|
||||||
|
'nkCast', # a type cast
|
||||||
|
'nkAddr', # a addr expression
|
||||||
|
# end of expressions
|
||||||
|
|
||||||
|
'nkAsgn', # a = b
|
||||||
|
'nkDefaultTypeParam', # `ident = typeDesc` in generic parameters
|
||||||
|
'nkGenericParams', # generic parameters
|
||||||
|
'nkFormalParams', # formal parameters
|
||||||
|
'nkOfInherit', # inherited from symbol
|
||||||
|
|
||||||
|
'nkModule', # the syntax tree of a module
|
||||||
|
'nkProcDef', # a proc
|
||||||
|
'nkConverterDef', # a converter
|
||||||
|
'nkMacroDef', # a macro
|
||||||
|
'nkTemplateDef', # a template
|
||||||
|
'nkIteratorDef', # an iterator
|
||||||
|
|
||||||
|
'nkOfBranch', # used inside case statements for (cond, action)-pairs
|
||||||
|
'nkElifBranch', # used in if statements
|
||||||
|
'nkExceptBranch', # an except section
|
||||||
|
'nkElse', # an else part
|
||||||
|
'nkMacroStmt', # a macro statement
|
||||||
|
'nkAsmStmt', # an assembler block
|
||||||
|
'nkPragma', # a pragma statement
|
||||||
|
'nkIfStmt', # an if statement
|
||||||
|
'nkWhenStmt', # a when statement
|
||||||
|
'nkForStmt', # a for statement
|
||||||
|
'nkWhileStmt', # a while statement
|
||||||
|
'nkCaseStmt', # a case statement
|
||||||
|
'nkVarSection', # a var section
|
||||||
|
'nkConstSection', # a const section
|
||||||
|
'nkConstDef', # a const definition
|
||||||
|
'nkTypeSection', # a type section (consists of type definitions)
|
||||||
|
'nkTypeDef', # a type definition
|
||||||
|
'nkYieldStmt', # the yield statement as a tree
|
||||||
|
'nkTryStmt', # a try statement
|
||||||
|
'nkFinally', # a finally section
|
||||||
|
'nkRaiseStmt', # a raise statement
|
||||||
|
'nkReturnStmt', # a return statement
|
||||||
|
'nkBreakStmt', # a break statement
|
||||||
|
'nkContinueStmt', # a continue statement
|
||||||
|
'nkBlockStmt', # a block statement
|
||||||
|
'nkGotoStmt', # used by the transformation pass; first son is a sym
|
||||||
|
# node containing a label
|
||||||
|
'nkDiscardStmt', # a discard statement
|
||||||
|
'nkStmtList', # a list of statements
|
||||||
|
'nkImportStmt', # an import statement
|
||||||
|
'nkFromStmt', # a from * import statement
|
||||||
|
'nkImportAs', # an `import xyx as abc` section
|
||||||
|
'nkIncludeStmt', # an include statement
|
||||||
|
'nkAccessStmt', # used internally for iterators
|
||||||
|
'nkCommentStmt', # a comment statement
|
||||||
|
'nkStmtListExpr', # a statement list followed by an expr; this is used
|
||||||
|
# to allow powerful multi-line templates
|
||||||
|
'nkBlockExpr', # a statement block ending in an expr; this is used
|
||||||
|
# to allowe powerful multi-line templates that open a
|
||||||
|
# temporary scope
|
||||||
|
'nkVm', # indicates a virtual instruction; integer field is
|
||||||
|
# used for the concrete opcode
|
||||||
|
|
||||||
|
# types as syntactic trees:
|
||||||
|
'nkTypeOfExpr',
|
||||||
|
'nkRecordTy',
|
||||||
|
'nkObjectTy',
|
||||||
|
'nkRecList', # list of record/object parts
|
||||||
|
'nkRecCase', # case section of record/object
|
||||||
|
'nkRecWhen', # when section of record/object
|
||||||
|
'nkRefTy',
|
||||||
|
'nkPtrTy',
|
||||||
|
'nkVarTy',
|
||||||
|
'nkProcTy',
|
||||||
|
'nkEnumTy',
|
||||||
|
'nkEnumFieldDef' # `ident = expr` in an enumeration
|
||||||
|
],
|
||||||
|
|
||||||
|
'SymKind': [
|
||||||
|
# the different symbols (start with the prefix sk);
|
||||||
|
# order is important for the documentation generator!
|
||||||
|
'skUnknownSym', # unknown symbol: used for parsing assembler blocks
|
||||||
|
'skConditional', # symbol for the preprocessor (may become obsolete)
|
||||||
|
'skDynLib', # symbol represents a dynamic library; this is used
|
||||||
|
# internally; it does not exist in Nimrod code
|
||||||
|
'skParam', # a parameter
|
||||||
|
'skTypeParam', # a type parameter; example: proc x[T]() <- `T`
|
||||||
|
'skTemp', # a temporary variable (introduced by compiler)
|
||||||
|
'skType', # a type
|
||||||
|
'skConst', # a constant
|
||||||
|
'skVar', # a variable
|
||||||
|
'skProc', # a proc
|
||||||
|
'skIterator', # an iterator
|
||||||
|
'skConverter', # a type converter
|
||||||
|
'skMacro', # a macro
|
||||||
|
'skTemplate', # a template
|
||||||
|
'skField', # a field in a record or object
|
||||||
|
'skEnumField', # an identifier in an enum
|
||||||
|
'skForVar', # a for loop variable
|
||||||
|
'skModule', # module identifier
|
||||||
|
'skLabel' # a label (for block statement)
|
||||||
|
]
|
||||||
|
}
|
||||||
29
data/basicopt.txt
Executable file
29
data/basicopt.txt
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
Usage::
|
||||||
|
nimrod command [options] inputfile [arguments]
|
||||||
|
Command::
|
||||||
|
compile compile project with default code generator (C)
|
||||||
|
compile_to_c compile project with C code generator
|
||||||
|
compile_to_cpp compile project with C++ code generator
|
||||||
|
doc generate the documentation for inputfile;
|
||||||
|
with --run switch opens it with $BROWSER
|
||||||
|
Arguments:
|
||||||
|
arguments are passed to the program being run (if --run option is selected)
|
||||||
|
Options:
|
||||||
|
-p, --path:PATH add path to search paths
|
||||||
|
-o, --out:FILE set the output filename
|
||||||
|
-d, --define:SYMBOL define a conditional symbol
|
||||||
|
-u, --undef:SYMBOL undefine a conditional symbol
|
||||||
|
-b, --force_build force rebuilding of all modules
|
||||||
|
--stack_trace:on|off code generation for stack trace ON|OFF
|
||||||
|
--line_trace:on|off code generation for line trace ON|OFF
|
||||||
|
--debugger:on|off turn Embedded Nimrod Debugger ON|OFF
|
||||||
|
-x, --checks:on|off code generation for all runtime checks ON|OFF
|
||||||
|
--range_checks:on|off code generation for range checks ON|OFF
|
||||||
|
--bound_checks:on|off code generation for bound checks ON|OFF
|
||||||
|
--overflow_checks:on|off code generation for over-/underflow checks ON|OFF
|
||||||
|
-a, --assertions:on|off code generation for assertions ON|OFF
|
||||||
|
--opt:none|speed|size optimize not at all or for speed|size
|
||||||
|
--app:console|gui|lib generate a console|GUI application or a shared lib
|
||||||
|
-r, --run run the compiled program with given arguments
|
||||||
|
--advanced show advanced command line switches
|
||||||
|
-h, --help show this help
|
||||||
1692
data/ccomps.txt
Executable file
1692
data/ccomps.txt
Executable file
File diff suppressed because it is too large
Load diff
22
data/changes.txt
Executable file
22
data/changes.txt
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
0.1.0
|
||||||
|
* new config system
|
||||||
|
* new build system
|
||||||
|
* source renderer
|
||||||
|
* pas2nim integrated
|
||||||
|
* support for C++
|
||||||
|
* local variables are always initialized
|
||||||
|
* Rod file reader and writer
|
||||||
|
* new --out, -o command line options
|
||||||
|
* fixed bug in nimconf.pas: we now have several
|
||||||
|
string token types
|
||||||
|
* changed nkIdentDef to nkIdentDefs
|
||||||
|
* added type(expr) in the parser and the grammer
|
||||||
|
* added template
|
||||||
|
* added command calls
|
||||||
|
* added case in records/objects
|
||||||
|
* added --skip_proj_cfg switch for nim.dpr
|
||||||
|
* added missing features to pasparse
|
||||||
|
* rewrote the source generator
|
||||||
|
* ``addr`` and ``cast`` are now keywords; grammar updated
|
||||||
|
* implemented ` notation; grammar updated
|
||||||
|
* specification replaced by a manual
|
||||||
19
data/keywords.txt
Executable file
19
data/keywords.txt
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
addr and as asm
|
||||||
|
block break
|
||||||
|
case cast const continue converter
|
||||||
|
discard div
|
||||||
|
elif else end enum except exception
|
||||||
|
finally for from generic
|
||||||
|
if implies import in include is isnot iterator
|
||||||
|
lambda
|
||||||
|
macro method mod
|
||||||
|
nil not notin
|
||||||
|
object of or out
|
||||||
|
proc ptr
|
||||||
|
raise record ref return
|
||||||
|
shl shr
|
||||||
|
template try type
|
||||||
|
var
|
||||||
|
when where while with without
|
||||||
|
xor
|
||||||
|
yield
|
||||||
176
data/magic.yml
Executable file
176
data/magic.yml
Executable file
|
|
@ -0,0 +1,176 @@
|
||||||
|
# All the magics of the system module:
|
||||||
|
# order has been changed!
|
||||||
|
[
|
||||||
|
'None',
|
||||||
|
'Defined',
|
||||||
|
'New',
|
||||||
|
'NewFinalize',
|
||||||
|
'Low',
|
||||||
|
'High',
|
||||||
|
'SizeOf',
|
||||||
|
'RegisterFinalizer',
|
||||||
|
'Succ',
|
||||||
|
'Pred',
|
||||||
|
'Inc',
|
||||||
|
'Dec',
|
||||||
|
'LengthOpenArray',
|
||||||
|
'LengthStr',
|
||||||
|
'LengthArray',
|
||||||
|
'LengthSeq',
|
||||||
|
'Incl',
|
||||||
|
'Excl',
|
||||||
|
'Card',
|
||||||
|
'Ord',
|
||||||
|
'Chr',
|
||||||
|
|
||||||
|
# binary arithmetic with and without overflow checking:
|
||||||
|
'AddI',
|
||||||
|
'SubI',
|
||||||
|
'MulI',
|
||||||
|
'DivI',
|
||||||
|
'ModI',
|
||||||
|
'AddI64',
|
||||||
|
'SubI64',
|
||||||
|
'MulI64',
|
||||||
|
'DivI64',
|
||||||
|
'ModI64',
|
||||||
|
|
||||||
|
# other binary arithmetic operators:
|
||||||
|
'ShrI',
|
||||||
|
'ShlI',
|
||||||
|
'BitandI',
|
||||||
|
'BitorI',
|
||||||
|
'BitxorI',
|
||||||
|
'MinI',
|
||||||
|
'MaxI',
|
||||||
|
'ShrI64',
|
||||||
|
'ShlI64',
|
||||||
|
'BitandI64',
|
||||||
|
'BitorI64',
|
||||||
|
'BitxorI64',
|
||||||
|
'MinI64',
|
||||||
|
'MaxI64',
|
||||||
|
'AddF64',
|
||||||
|
'SubF64',
|
||||||
|
'MulF64',
|
||||||
|
'DivF64',
|
||||||
|
'MinF64',
|
||||||
|
'MaxF64',
|
||||||
|
'AddU',
|
||||||
|
'SubU',
|
||||||
|
'MulU',
|
||||||
|
'DivU',
|
||||||
|
'ModU',
|
||||||
|
'AddU64',
|
||||||
|
'SubU64',
|
||||||
|
'MulU64',
|
||||||
|
'DivU64',
|
||||||
|
'ModU64',
|
||||||
|
|
||||||
|
# comparison operators:
|
||||||
|
'EqI',
|
||||||
|
'LeI',
|
||||||
|
'LtI',
|
||||||
|
'EqI64',
|
||||||
|
'LeI64',
|
||||||
|
'LtI64',
|
||||||
|
'EqF64',
|
||||||
|
'LeF64',
|
||||||
|
'LtF64',
|
||||||
|
'LeU',
|
||||||
|
'LtU',
|
||||||
|
'LeU64',
|
||||||
|
'LtU64',
|
||||||
|
'EqEnum',
|
||||||
|
'LeEnum',
|
||||||
|
'LtEnum',
|
||||||
|
'EqCh',
|
||||||
|
'LeCh',
|
||||||
|
'LtCh',
|
||||||
|
'EqB',
|
||||||
|
'LeB',
|
||||||
|
'LtB',
|
||||||
|
'EqRef',
|
||||||
|
'EqProc',
|
||||||
|
'EqUntracedRef',
|
||||||
|
'LePtr',
|
||||||
|
'LtPtr',
|
||||||
|
'EqCString',
|
||||||
|
'Xor',
|
||||||
|
|
||||||
|
# unary arithmetic with and without overflow checking:
|
||||||
|
'UnaryMinusI',
|
||||||
|
'UnaryMinusI64',
|
||||||
|
'AbsI',
|
||||||
|
'AbsI64',
|
||||||
|
|
||||||
|
# other unary operations:
|
||||||
|
'Not',
|
||||||
|
'UnaryPlusI',
|
||||||
|
'BitnotI',
|
||||||
|
'UnaryPlusI64',
|
||||||
|
'BitnotI64',
|
||||||
|
'UnaryPlusF64',
|
||||||
|
'UnaryMinusF64',
|
||||||
|
'AbsF64',
|
||||||
|
'Ze',
|
||||||
|
'Ze64',
|
||||||
|
'ToU8',
|
||||||
|
'ToU16',
|
||||||
|
'ToU32',
|
||||||
|
'ToFloat',
|
||||||
|
'ToBiggestFloat',
|
||||||
|
'ToInt',
|
||||||
|
'ToBiggestInt',
|
||||||
|
|
||||||
|
# special ones:
|
||||||
|
'And',
|
||||||
|
'Or',
|
||||||
|
'EqStr',
|
||||||
|
'LeStr',
|
||||||
|
'LtStr',
|
||||||
|
'EqSet',
|
||||||
|
'LeSet',
|
||||||
|
'LtSet',
|
||||||
|
'MulSet',
|
||||||
|
'PlusSet',
|
||||||
|
'MinusSet',
|
||||||
|
'SymDiffSet',
|
||||||
|
'ConStrStr',
|
||||||
|
'ConArrArr',
|
||||||
|
'ConArrT',
|
||||||
|
'ConTArr',
|
||||||
|
'ConTT',
|
||||||
|
'Slice',
|
||||||
|
'AppendStrCh',
|
||||||
|
'AppendStrStr',
|
||||||
|
'AppendSeqElem',
|
||||||
|
'AppendSeqSeq',
|
||||||
|
'InRange',
|
||||||
|
'InSet',
|
||||||
|
'Is',
|
||||||
|
'Asgn',
|
||||||
|
'Repr',
|
||||||
|
'Exit',
|
||||||
|
'SetLengthStr',
|
||||||
|
'SetLengthSeq',
|
||||||
|
'Assert',
|
||||||
|
'Swap',
|
||||||
|
|
||||||
|
# magic type constructors:
|
||||||
|
'Array',
|
||||||
|
'OpenArray',
|
||||||
|
'Range',
|
||||||
|
'Tuple',
|
||||||
|
'Set',
|
||||||
|
'Seq',
|
||||||
|
|
||||||
|
# magic constants:
|
||||||
|
'CompileDate',
|
||||||
|
'CompileTime',
|
||||||
|
'NimrodVersion',
|
||||||
|
'NimrodMajor',
|
||||||
|
'NimrodMinor',
|
||||||
|
'NimrodPatch',
|
||||||
|
'CpuEndian'
|
||||||
|
]
|
||||||
282
data/messages.yml
Executable file
282
data/messages.yml
Executable file
|
|
@ -0,0 +1,282 @@
|
||||||
|
# This file contains all the messages of the Nimrod compiler
|
||||||
|
# (c) 2008 Andreas Rumpf
|
||||||
|
|
||||||
|
[
|
||||||
|
# fatal errors:
|
||||||
|
{'errUnknown': 'unknown error'},
|
||||||
|
{'errIllFormedAstX': 'illformed AST: $1'},
|
||||||
|
{'errCannotOpenFile': "cannot open '$1'"},
|
||||||
|
{'errInternal': 'internal error: $1'},
|
||||||
|
|
||||||
|
# other errors:
|
||||||
|
{'errGenerated': '$1'},
|
||||||
|
{'errXCompilerDoesNotSupportCpp': "'$1' compiler does not support C++"},
|
||||||
|
|
||||||
|
# errors:
|
||||||
|
{'errStringLiteralExpected': 'string literal expected'},
|
||||||
|
{'errIntLiteralExpected': 'integer literal expected'},
|
||||||
|
{'errInvalidCharacterConstant': 'invalid character constant'},
|
||||||
|
{'errClosingTripleQuoteExpected':
|
||||||
|
'closing """ expected, but end of file reached'},
|
||||||
|
{'errClosingQuoteExpected': 'closing " expected'},
|
||||||
|
{'errTabulatorsAreNotAllowed': 'tabulators are not allowed'},
|
||||||
|
{'errInvalidToken': 'invalid token: $1'},
|
||||||
|
{'errLineTooLong': 'line too long'},
|
||||||
|
{'errInvalidNumber': '$1 is not a valid number'},
|
||||||
|
{'errNumberOutOfRange': '$1 is too large or too small'},
|
||||||
|
{'errNnotAllowedInCharacter': '\\n not allowed in character literal'},
|
||||||
|
{'errClosingBracketExpected': "closing ']' expected, but end of file reached"},
|
||||||
|
{'errMissingFinalQuote': "missing final '"},
|
||||||
|
{'errIdentifierExpected': "identifier expected, but found '$1'"},
|
||||||
|
{'errOperatorExpected': "operator expected, but found '$1'"},
|
||||||
|
{'errTokenExpected': "'$1' expected"},
|
||||||
|
{'errStringAfterIncludeExpected': "string after 'include' expected"},
|
||||||
|
{'errRecursiveInclude': "recursive include file: '$1'"},
|
||||||
|
{'errAtIfExpected': "'@if' expected"},
|
||||||
|
{'errAtIfExpectedBeforeElse': "'@if' expected before '@else'"},
|
||||||
|
{'errAtIfExpectedBeforeElif': "'@if' expected before '@elif'"},
|
||||||
|
{'errAtEndExpected': "'@end' expected"},
|
||||||
|
{'errOnOrOffExpected': "'on' or 'off' expected"},
|
||||||
|
{'errNoneSpeedOrSizeExpected': "'none', 'speed' or 'size' expected"},
|
||||||
|
{'errInvalidPragma': 'invalid pragma'},
|
||||||
|
{'errUnknownPragma': "unknown pragma: '$1'"},
|
||||||
|
{'errPragmaXHereNotAllowed': "pragma '$1' here not allowed"},
|
||||||
|
{'errUnknownDirective': "unknown directive: '$1'"},
|
||||||
|
{'errInvalidDirective': 'invalid directive'},
|
||||||
|
{'errAtPopWithoutPush': "'pop' without a 'push' pragma"},
|
||||||
|
{'errEmptyAsm': 'empty asm statement makes no sense'},
|
||||||
|
{'errAsgnInvalidInExpr': "'=' invalid in an expression; probably '==' meant"},
|
||||||
|
{'errInvalidIndentation': 'invalid indentation'},
|
||||||
|
{'errExceptionExpected': 'exception expected'},
|
||||||
|
{'errExceptionAlreadyHandled': 'exception already handled'},
|
||||||
|
{'errReturnNotAllowedHere': "'return' only allowed in routine"},
|
||||||
|
{'errYieldNotAllowedHere': "'yield' only allowed in iterator"},
|
||||||
|
{'errInvalidNumberOfYieldExpr': "invalid number of 'yield' expresions"},
|
||||||
|
{'errReturnInvalidInIterator': "'return' not allowed in iterator"},
|
||||||
|
{'errCannotReturnExpr': 'current routine cannot return an expression'},
|
||||||
|
{'errAttemptToRedefine': "attempt to redefine '$1'"},
|
||||||
|
{'errStmtInvalidAfterReturn':
|
||||||
|
"statement not allowed after 'return', 'break' or 'raise'"},
|
||||||
|
{'errStmtExpected': 'statement expected'},
|
||||||
|
{'errYieldOnlyInInterators': "'yield' statement is only allowed in iterators"},
|
||||||
|
{'errInvalidLabel': "'$1' is no label"},
|
||||||
|
{'errInvalidCmdLineOption': "invalid command line option: '$1'"},
|
||||||
|
{'errCmdLineArgExpected': "argument for command line option expected: '$1'"},
|
||||||
|
{'errInvalidVarSubstitution': "invalid variable substitution in '$1'"},
|
||||||
|
{'errUnknownVar': "unknown variable: '$1'"},
|
||||||
|
{'errUnknownCcompiler': "unknown C compiler: '$1'"},
|
||||||
|
{'errOnOrOffExpectedButXFound': "'on' or 'off' expected, but '$1' found"},
|
||||||
|
{'errNoneBoehmRefcExpectedButXFound':
|
||||||
|
"'none', 'boehm' or 'refc' expected, but '$1' found"},
|
||||||
|
{'errNoneSpeedOrSizeExpectedButXFound':
|
||||||
|
"'none', 'speed' or 'size' expected, but '$1' found"},
|
||||||
|
{'errGuiConsoleOrLibExpectedButXFound':
|
||||||
|
"'gui', 'console' or 'lib' expected, but '$1' found"},
|
||||||
|
{'errUnknownOS': "unknown OS: '$1'"},
|
||||||
|
{'errUnknownCPU': "unknown CPU: '$1'"},
|
||||||
|
{'errGenOutExpectedButXFound':
|
||||||
|
"'c', 'c++' or 'yaml' expected, but '$1' found"},
|
||||||
|
{'errArgsNeedRunOption':
|
||||||
|
"arguments can only be given if the '--run' option is selected"},
|
||||||
|
{'errInvalidMultipleAsgn': 'multiple assignment is not allowed'},
|
||||||
|
{'errColonOrEqualsExpected': "':' or '=' expected, but found '$1'"},
|
||||||
|
{'errExprExpected': "expression expected, but found '$1'"},
|
||||||
|
{'errUndeclaredIdentifier': "undeclared identifier: '$1'"},
|
||||||
|
{'errUseQualifier': "ambigious identifier: '$1' -- use a qualifier"},
|
||||||
|
{'errTwiceForwarded': "'$1' is forwarded twice"},
|
||||||
|
{'errTypeExpected': 'type expected'},
|
||||||
|
{'errSystemNeeds': "system module needs '$1'"},
|
||||||
|
{'errExecutionOfProgramFailed': 'execution of an external program failed'},
|
||||||
|
{'errNotOverloadable': "overloaded '$1' leads to ambigious calls"},
|
||||||
|
{'errInvalidArgForX': "invalid argument for '$1'"},
|
||||||
|
{'errStmtHasNoEffect': 'statement has no effect'},
|
||||||
|
{'errXExpectsTypeOrValue': "'$1' expects a type or value"},
|
||||||
|
{'errXExpectsArrayType': "'$1' expects an array type"},
|
||||||
|
{'errIteratorCannotBeInstantiated':
|
||||||
|
"'$1' cannot be instantiated because its body has not been compiled yet"},
|
||||||
|
{'errExprWithNoTypeCannotBeConverted':
|
||||||
|
'expression with no type cannot be converted'},
|
||||||
|
{'errExprWithNoTypeCannotBeCasted': 'expression with no type cannot be casted'},
|
||||||
|
{'errConstantDivisionByZero': 'constant division by zero'},
|
||||||
|
{'errOrdinalTypeExpected': 'ordinal type expected'},
|
||||||
|
{'errOrdinalOrFloatTypeExpected': 'ordinal or float type expected'},
|
||||||
|
{'errOverOrUnderflow': 'over- or underflow'},
|
||||||
|
{'errCannotEvalXBecauseIncompletelyDefined':
|
||||||
|
"cannot evalutate '$1' because type is not defined completely"},
|
||||||
|
{'errChrExpectsRange0_255': "'chr' expects an int in the range 0..255"},
|
||||||
|
{'errStaticAssertFailed': "'staticAssert' failed: condition is false"},
|
||||||
|
{'errStaticAssertCannotBeEval':
|
||||||
|
"argument to 'staticAssert' cannot be evaluated at compile time"},
|
||||||
|
{'errDotRequiresRecordOrObjectType': "'.' requires a record or object type"},
|
||||||
|
{'errUndeclaredFieldX': "undeclared field: '$1'"},
|
||||||
|
{'errIndexNoIntType': 'index has to be an integer type'},
|
||||||
|
{'errIndexOutOfBounds': 'index out of bounds'},
|
||||||
|
{'errIndexTypesDoNotMatch': 'index types do not match'},
|
||||||
|
{'errBracketsInvalidForType': "'[]' operator invalid for this type"},
|
||||||
|
{'errValueOutOfSetBounds': 'value out of set bounds'},
|
||||||
|
{'errFieldInitTwice': "field initialized twice: '$1'"},
|
||||||
|
{'errFieldNotInit': "field '$1' not initialized"},
|
||||||
|
{'errExprCannotBeCalled': 'expression cannot be called'},
|
||||||
|
{'errExprHasNoType': 'expression has no type'},
|
||||||
|
{'errExprXHasNoType': "expression '$1' has no type"},
|
||||||
|
{'errCastNotInSafeMode': "'cast' not allowed in safe mode"},
|
||||||
|
{'errExprCannotBeCastedToX': 'expression cannot be casted to $1'},
|
||||||
|
{'errUndefinedPrefixOpr': 'undefined prefix operator: $1'},
|
||||||
|
{'errCommaOrParRiExpected': "',' or ')' expected"},
|
||||||
|
{'errCurlyLeOrParLeExpected': "'{' or '(' expected"},
|
||||||
|
{'errSectionExpected': "section ('type', 'proc', etc.) expected"},
|
||||||
|
{'errImplemenationExpected': "'implementation' or end of file expected"},
|
||||||
|
{'errRangeExpected': 'range expected'},
|
||||||
|
{'errInvalidTypeDescription': 'invalid type description'},
|
||||||
|
{'errAttemptToRedefineX': "attempt to redefine '$1'"},
|
||||||
|
{'errMagicOnlyInSystem': "'magic' only allowed in system module"},
|
||||||
|
{'errUnknownOperatorX': "unkown operator: '$1'"},
|
||||||
|
{'errPowerOfTwoExpected': 'power of two expected'},
|
||||||
|
{'errStringMayNotBeEmpty': 'string literal may not be empty'},
|
||||||
|
{'errCallConvExpected': 'calling convention expected'},
|
||||||
|
{'errProcOnlyOneCallConv': 'a proc can only have one calling convention'},
|
||||||
|
{'errSymbolMustBeImported': "symbol must be imported if 'lib' pragma is used"},
|
||||||
|
{'errExprMustBeBool': "expression must be of type 'bool'"},
|
||||||
|
{'errConstExprExpected': 'constant expression expected'},
|
||||||
|
{'errDuplicateCaseLabel': 'duplicate case label'},
|
||||||
|
{'errRangeIsEmpty': 'range is empty'},
|
||||||
|
{'errSelectorMustBeOfCertainTypes':
|
||||||
|
'selector must be of an ordinal type, real or string'},
|
||||||
|
{'errSelectorMustBeOrdinal':
|
||||||
|
'selector must be of an ordinal type'},
|
||||||
|
{'errOrdXMustNotBeNegative': 'ord($1) must not be negative'},
|
||||||
|
{'errLenXinvalid': 'len($1) must be less than 32768'},
|
||||||
|
{'errWrongNumberOfLoopVariables': 'wrong number of loop variables'},
|
||||||
|
{'errExprCannotBeRaised': 'only objects can be raised'},
|
||||||
|
{'errBreakOnlyInLoop': "'break' only allowed in loop construct"},
|
||||||
|
{'errTypeXhasUnknownSize': "type '$1' has unknown size"},
|
||||||
|
{'errConstNeedsConstExpr':
|
||||||
|
'a constant can only be initialized with a constant expression'},
|
||||||
|
{'errConstNeedsValue': 'a constant needs a value'},
|
||||||
|
{'errResultCannotBeOpenArray': 'the result type cannot be on open array'},
|
||||||
|
{'errSizeTooBig': "computing the type's size produced an overflow"},
|
||||||
|
{'errSetTooBig': 'set is too large'},
|
||||||
|
{'errBaseTypeMustBeOrdinal': 'base type of a set must be an ordinal'},
|
||||||
|
{'errInheritanceOnlyWithObjects': 'inheritance only works with an object'},
|
||||||
|
{'errInheritanceOnlyWithEnums': 'inheritance only works with an enum'},
|
||||||
|
{'errIllegalRecursionInTypeX': "illegal recursion in type '$1'"},
|
||||||
|
{'errCannotInstantiateX': "cannot instantiate: '$1'"},
|
||||||
|
{'errExprHasNoAddress': 'expression has no address'},
|
||||||
|
{'errVarForOutParamNeeded':
|
||||||
|
'to an out parameter a variable needs to be passed'},
|
||||||
|
{'errPureTypeMismatch': 'type mismatch'},
|
||||||
|
{'errTypeMismatch': 'type mismatch: got ('},
|
||||||
|
{'errButExpected': 'but expected one of: '},
|
||||||
|
{'errButExpectedX': "but expected '$1'"},
|
||||||
|
{'errAmbigiousCallXYZ': 'ambigious call; both $1 and $2 match for: $3'},
|
||||||
|
{'errWrongNumberOfTypeParams': 'wrong number of type parameters'},
|
||||||
|
{'errOutParamNoDefaultValue': 'out parameters cannot have default values'},
|
||||||
|
{'errInlineProcHasNoAddress': 'an inline proc has no address'},
|
||||||
|
{'errXCannotBeInParamDecl': '$1 cannot be declared in parameter declaration'},
|
||||||
|
{'errPragmaOnlyInHeaderOfProc':
|
||||||
|
'pragmas are only in the header of a proc allowed'},
|
||||||
|
{'errImportedProcCannotHaveImpl':
|
||||||
|
'an imported proc cannot have an implementation'},
|
||||||
|
{'errImplOfXNotAllowed': "implementation of '$1' is not allowed here"},
|
||||||
|
{'errImplOfXexpected': "implementation of '$1' expected"},
|
||||||
|
{'errDiscardValue': 'value returned by statement has to be discarded'},
|
||||||
|
{'errInvalidDiscard': 'statement returns no value that can be discarded'},
|
||||||
|
{'errUnknownPrecedence':
|
||||||
|
"unknown precedence for operator; use 'infix: prec' pragma"},
|
||||||
|
{'errIllegalConvFromXtoY': 'conversion from $1 to $2 is invalid'},
|
||||||
|
{'errTypeMismatchExpectedXGotY': "type mismatch: expected '$1', but got '$2'"},
|
||||||
|
{'errCannotBindXTwice': "cannot bind parameter '$1' twice"},
|
||||||
|
{'errInvalidOrderInEnumX': "invalid order in enum '$1'"},
|
||||||
|
{'errEnumXHasWholes': "enum '$1' has wholes"},
|
||||||
|
{'errExceptExpected': "'except' or 'finally' expected"},
|
||||||
|
{'errInvalidTry': "after catch all 'except' or 'finally' no section may follow"},
|
||||||
|
{'errEofExpectedButXFound': "end of file expected, but found token '$1'"},
|
||||||
|
{'errOptionExpected': "option expected, but found '$1'"},
|
||||||
|
{'errCannotEvaluateForwardConst': 'cannot evaluate forwarded constant'},
|
||||||
|
{'errXisNoLabel': "'$1' is not a label"},
|
||||||
|
{'errXNeedsConcreteType': "'$1' needs to be of a non-generic type"},
|
||||||
|
{'errNotAllCasesCovered': 'not all cases are covered'},
|
||||||
|
{'errStringRange': 'string range in case statement not allowed'},
|
||||||
|
{'errUnkownSubstitionVar': "unknown substitution variable: '$1'"},
|
||||||
|
{'errComplexStmtRequiresInd': 'complex statement requires indentation'},
|
||||||
|
{'errXisNotCallable': "'$1' is not callable"},
|
||||||
|
{'errNoPragmasAllowedForX': 'no pragmas allowed for $1'},
|
||||||
|
{'errNoGenericParamsAllowedForX': 'no generic parameters allowed for $1'},
|
||||||
|
{'errInvalidParamKindX': "invalid param kind: '$1'"},
|
||||||
|
{'errDefaultArgumentInvalid': 'default argument invalid'},
|
||||||
|
{'errNamedParamHasToBeIdent': 'named parameter has to be an identifier'},
|
||||||
|
{'errNoReturnTypeForX': 'no return type for $1 allowed'},
|
||||||
|
{'errConvNeedsOneArg': 'a type conversion needs exactly one argument'},
|
||||||
|
{'errInvalidPragmaX': 'invalid pragma: $1'},
|
||||||
|
{'errXNotAllowedHere': '$1 here not allowed'},
|
||||||
|
{'errInvalidControlFlowX': 'invalid control flow: $1'},
|
||||||
|
{'errATypeHasNoValue': 'a type has no value'},
|
||||||
|
{'errXisNoType': "'$1' is no type"},
|
||||||
|
{'errCircumNeedsPointer': "'^' needs a pointer or reference type"},
|
||||||
|
{'errInvalidContextForBuiltinX': "invalid context for builtin '$1'"},
|
||||||
|
{'errInvalidExpression': 'invalid expression'},
|
||||||
|
{'errInvalidExpressionX': "invalid expression: '$1'"},
|
||||||
|
{'errEnumHasNoValueX': "enum has no value '$1'"},
|
||||||
|
{'errNamedExprExpected': 'named expression expected'},
|
||||||
|
{'errNamedExprNotAllowed': 'named expression here not allowed'},
|
||||||
|
{'errXExpectsOneTypeParam': "'$1' expects one type parameter"},
|
||||||
|
{'errArrayExpectsTwoTypeParams': 'array expects two type parameters'},
|
||||||
|
{'errInvalidVisibilityX': "invalid invisibility: '$1'"},
|
||||||
|
{'errInitHereNotAllowed': 'initialization here not allowed'},
|
||||||
|
{'errXCannotBeAssignedTo': "'$1' cannot be assigned to"},
|
||||||
|
{'errIteratorNotAllowed':
|
||||||
|
"iterators can only be defined at the module's top level"},
|
||||||
|
{'errIteratorNeedsImplementation': 'iterator needs an implementation'},
|
||||||
|
{'errIteratorNeedsReturnType': 'iterator needs a return type'},
|
||||||
|
{'errInvalidCommandX': "invalid command: '$1'"},
|
||||||
|
{'errXOnlyAtModuleScope': "'$1' is only allowed at top level"},
|
||||||
|
{'errTypeXNeedsImplementation': "type '$1' needs an implementation"},
|
||||||
|
{'errTemplateInstantiationTooNested': 'template instantiation too nested'},
|
||||||
|
{'errInstantiationFrom': 'instantiation from here'},
|
||||||
|
{'errInvalidIndexValueForTuple': 'invalid index value for tuple subscript'},
|
||||||
|
{'errCommandExpectsFilename': 'command expects a filename argument'},
|
||||||
|
{'errXExpected': "'$1' expected"},
|
||||||
|
{'errInvalidSectionStart': 'invalid section start'},
|
||||||
|
{'errGridTableNotImplemented': 'grid table is not implemented'},
|
||||||
|
{'errGeneralParseError': 'general parse error'},
|
||||||
|
{'errNewSectionExpected': 'new section expected'},
|
||||||
|
{'errWhitespaceExpected': "whitespace expected, got '$1'"},
|
||||||
|
{'errXisNoValidIndexFile': "'$1' is no valid index file"},
|
||||||
|
{'errCannotRenderX': "cannot render reStructuredText element '$1'"},
|
||||||
|
|
||||||
|
# user error message:
|
||||||
|
{'errUser': '$1'},
|
||||||
|
|
||||||
|
# warnings:
|
||||||
|
{'warnCannotOpenFile': "cannot open '$1'"},
|
||||||
|
{'warnOctalEscape':
|
||||||
|
'octal escape sequences do not exist; leading zero is ignored'},
|
||||||
|
{'warnXIsNeverRead': "'$1' is never read"},
|
||||||
|
{'warnXmightNotBeenInit': "'$1' might not have been initialized"},
|
||||||
|
{'warnCannotWriteMO2': "cannot write file '$1'"},
|
||||||
|
{'warnCannotReadMO2': "cannot read file '$1'"},
|
||||||
|
{'warnDeprecated': "'$1' is deprecated"},
|
||||||
|
{'warnSmallLshouldNotBeUsed':
|
||||||
|
"'l' should not be used as an identifier; may look like '1' (one)"},
|
||||||
|
{'warnUnknownMagic': "unknown magic '$1' might crash the compiler"},
|
||||||
|
{'warnRedefinitionOfLabel': "redefinition of label '$1'"},
|
||||||
|
{'warnUnknownSubstitutionX': "unknown substitution '$1'"},
|
||||||
|
{'warnLanguageXNotSupported': "language '$1' not supported"},
|
||||||
|
{'warnCommentXIgnored': "comment '$1' ignored"},
|
||||||
|
# user warning message:
|
||||||
|
{'warnUser': '$1'},
|
||||||
|
|
||||||
|
# hints:
|
||||||
|
{'hintSuccess': 'operation successful'},
|
||||||
|
{'hintLineTooLong': 'line too long'},
|
||||||
|
{'hintXDeclaredButNotUsed': "'$1' is declared but not used"},
|
||||||
|
{'hintConvToBaseNotNeeded': 'conversion to base object is not needed'},
|
||||||
|
{'hintConvFromXtoItselfNotNeeded': 'conversion from $1 to itself is pointless'},
|
||||||
|
{'hintExprAlwaysX': "expression evaluates always to '$1'"},
|
||||||
|
{'hintMo2FileInvalid': "mo2 file '$1' is invalid"},
|
||||||
|
{'hintModuleHasChanged': "module '$1' has been changed"},
|
||||||
|
{'hintCannotOpenMo2File': "mo2 file '$1' does not exist"},
|
||||||
|
|
||||||
|
# user hint message:
|
||||||
|
{'hintUser': '$1'}
|
||||||
|
]
|
||||||
26
data/pas_keyw.yml
Executable file
26
data/pas_keyw.yml
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Object Pascal keywords for the Pascal scanner that is part of the
|
||||||
|
# Nimrod distribution
|
||||||
|
# (c) Andreas Rumpf 2007
|
||||||
|
[
|
||||||
|
"and", "array", "as", "asm",
|
||||||
|
"begin",
|
||||||
|
"case", "class", "const", "constructor",
|
||||||
|
"destructor", "div", "do", "downto",
|
||||||
|
"else", "end", "except", "exports",
|
||||||
|
"finalization", "finally", "for", "function",
|
||||||
|
"goto",
|
||||||
|
"if", "implementation", "in", "inherited", "initialization", "inline",
|
||||||
|
"interface", "is",
|
||||||
|
"label", "library",
|
||||||
|
"mod",
|
||||||
|
"nil", "not",
|
||||||
|
"object", "of", "or", "out",
|
||||||
|
"packed", "procedure", "program", "property",
|
||||||
|
"raise", "record", "repeat", "resourcestring",
|
||||||
|
"set", "shl", "shr",
|
||||||
|
"then", "threadvar", "to", "try", "type",
|
||||||
|
"unit", "until", "uses",
|
||||||
|
"var",
|
||||||
|
"while", "with",
|
||||||
|
"xor"
|
||||||
|
]
|
||||||
5
data/readme.txt
Executable file
5
data/readme.txt
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
This directory contains data files in a format called YAML_. These files
|
||||||
|
are required for building Nimrod.
|
||||||
|
|
||||||
|
|
||||||
|
.. _YAML: http://www.yaml.org/
|
||||||
1
dist/empty.txt
vendored
Executable file
1
dist/empty.txt
vendored
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
This file keeps several tools from deleting this subdirectory.
|
||||||
26
doc/docs.txt
Executable file
26
doc/docs.txt
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
"Incorrect documentation is often worse than no documentation."
|
||||||
|
-- Bertrand Meyer
|
||||||
|
|
||||||
|
The documentation consists of several documents:
|
||||||
|
|
||||||
|
- | `Nimrod manual <manual.html>`_
|
||||||
|
| Read this to get to know the Nimrod programming system.
|
||||||
|
|
||||||
|
- | `User guide for the Nimrod Compiler <nimrodc.html>`_
|
||||||
|
| The user guide lists command line arguments, Nimrodc's special features, etc.
|
||||||
|
|
||||||
|
- | `User guide for the Embedded Nimrod Debugger <endb.html>`_
|
||||||
|
| This document describes how to use the Embedded debugger. The embedded
|
||||||
|
debugger currently has no GUI. Please help!
|
||||||
|
|
||||||
|
- | `Nimrod library documentation <lib.html>`_
|
||||||
|
| This document describes Nimrod's standard library.
|
||||||
|
|
||||||
|
- | `Nimrod internal documentation <intern.html>`_
|
||||||
|
| The internal documentation describes how the compiler is implemented. Read
|
||||||
|
this if you want to hack the compiler or develop advanced macros.
|
||||||
|
|
||||||
|
- | `Index <theindex.html>`_
|
||||||
|
| The generated index. Often the quickest way to find the piece of
|
||||||
|
information you need.
|
||||||
|
|
||||||
174
doc/endb.txt
Executable file
174
doc/endb.txt
Executable file
|
|
@ -0,0 +1,174 @@
|
||||||
|
===========================================
|
||||||
|
Embedded Nimrod Debugger User Guide
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Nimrod comes with a platform independant debugger -
|
||||||
|
the `Embedded Nimrod Debugger`:idx: (`ENDB`:idx:). The debugger is
|
||||||
|
*embedded* into your executable if it has been
|
||||||
|
compiled with the ``--debugger:on`` command line option.
|
||||||
|
This also defines the conditional symbol ``ENDB`` for you.
|
||||||
|
|
||||||
|
Note: You must not compile your program with the ``--app:gui``
|
||||||
|
command line option because then there is no console
|
||||||
|
available for the debugger.
|
||||||
|
|
||||||
|
If you start your program the debugger will immediately show
|
||||||
|
a prompt on the console. You can now enter a command. The next sections
|
||||||
|
deal with the possible commands. As usual for Nimrod for all commands
|
||||||
|
underscores and case do not matter. Optional components of a command
|
||||||
|
are listed in brackets ``[...]`` here.
|
||||||
|
|
||||||
|
|
||||||
|
General Commands
|
||||||
|
================
|
||||||
|
|
||||||
|
``h``, ``help``
|
||||||
|
Display a quick reference of the possible commands.
|
||||||
|
|
||||||
|
``q``, ``quit``
|
||||||
|
Quit the debugger and the program.
|
||||||
|
|
||||||
|
<ENTER>
|
||||||
|
(Without any typed command) repeat the previous debugger command.
|
||||||
|
If there is no previous command, ``step_into`` is assumed.
|
||||||
|
|
||||||
|
Executing Commands
|
||||||
|
==================
|
||||||
|
|
||||||
|
``s``, ``step_into``
|
||||||
|
Single step, stepping into routine calls.
|
||||||
|
|
||||||
|
``n``, ``step_over``
|
||||||
|
Single step, without stepping into routine calls.
|
||||||
|
|
||||||
|
``f``, ``skip_current``
|
||||||
|
Continue execution until the current routine finishes.
|
||||||
|
|
||||||
|
``c``, ``continue``
|
||||||
|
Continue execution until the next breakpoint.
|
||||||
|
|
||||||
|
``i``, ``ignore``
|
||||||
|
Continue execution, ignore all breakpoints. This is effectively quitting
|
||||||
|
the debugger and runs the program until it finishes.
|
||||||
|
|
||||||
|
|
||||||
|
Breakpoint Commands
|
||||||
|
===================
|
||||||
|
|
||||||
|
``b``, ``setbreak`` <identifier> [fromline [toline]] [file]
|
||||||
|
Set a new breakpoint named 'identifier' for the given file
|
||||||
|
and line numbers. If no file is given, the current execution point's
|
||||||
|
filename is used. If the filename has no extension, ``.nim`` is
|
||||||
|
appended for your convenience.
|
||||||
|
If no line numbers are given, the current execution point's
|
||||||
|
line is used. If both ``fromline`` and ``toline`` are given the
|
||||||
|
breakpoint contains a line number range. Some examples if it is still
|
||||||
|
unclear:
|
||||||
|
|
||||||
|
* ``b br1 12 15 thallo`` creates a breakpoint named ``br1`` that
|
||||||
|
will be triggered if the instruction pointer reaches one of the
|
||||||
|
lines 12-15 in the file ``thallo.nim``.
|
||||||
|
* ``b br1 12 thallo`` creates a breakpoint named ``br1`` that
|
||||||
|
will be triggered if the instruction pointer reaches the
|
||||||
|
line 12 in the file ``thallo.nim``.
|
||||||
|
* ``b br1 12`` creates a breakpoint named ``br1`` that
|
||||||
|
will be triggered if the instruction pointer reaches the
|
||||||
|
line 12 in the current file.
|
||||||
|
* ``b br1`` creates a breakpoint named ``br1`` that
|
||||||
|
will be triggered if the instruction pointer reaches the
|
||||||
|
current line in the current file again.
|
||||||
|
|
||||||
|
``breakpoints``
|
||||||
|
Display the entire breakpoint list.
|
||||||
|
|
||||||
|
``disable`` <identifier>
|
||||||
|
Disable a breakpoint. It remains disabled until you turn it on again
|
||||||
|
with the ``enable`` command.
|
||||||
|
|
||||||
|
``enable`` <identifier>
|
||||||
|
Enable a breakpoint.
|
||||||
|
|
||||||
|
Often it happens when debugging that you keep retyping the breakpoints again
|
||||||
|
and again because they are lost when you restart your program. This is not
|
||||||
|
necessary: A special pragma has been defined for this:
|
||||||
|
|
||||||
|
|
||||||
|
The ``{.breakpoint.}`` pragma
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The `breakpoint`:idx: pragma is syntactically a statement. It can be used
|
||||||
|
to mark the *following line* as a breakpoint:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
write("1")
|
||||||
|
{.breakpoint: "before_write_2".}
|
||||||
|
write("2")
|
||||||
|
|
||||||
|
The name of the breakpoint here is ``before_write_2``. Of course the
|
||||||
|
breakpoint's name is optional - the compiler will generate one for you
|
||||||
|
if you leave it out.
|
||||||
|
|
||||||
|
Code for the ``breakpoint`` pragma is only generated if the debugger
|
||||||
|
is turned on, so you don't need to remove it from your source code after
|
||||||
|
debugging.
|
||||||
|
|
||||||
|
|
||||||
|
Data Display Commands
|
||||||
|
=====================
|
||||||
|
|
||||||
|
``e``, ``eval`` <exp>
|
||||||
|
Evaluate the expression <exp>. Note that ENDB has no full-blown expression
|
||||||
|
evaluator built-in. So expressions are limited:
|
||||||
|
|
||||||
|
* To display global variables prefix their names with their
|
||||||
|
owning module: ``nim1.globalVar``
|
||||||
|
* To display local variables or parameters just type in
|
||||||
|
their name: ``localVar``. If you want to inspect variables that are not
|
||||||
|
in the current stack frame, use the ``up`` or ``down`` command.
|
||||||
|
|
||||||
|
Unfortunately, only inspecting variables is possible at the moment. Maybe
|
||||||
|
a future version will implement a full-blown Nimrod expression evaluator,
|
||||||
|
but this is not easy to do and would bloat the debugger's code.
|
||||||
|
|
||||||
|
Since displaying the whole data structures is often not needed and
|
||||||
|
painfully slow, the debugger uses a *maximal display depth* concept for
|
||||||
|
displaying.
|
||||||
|
|
||||||
|
You can alter the *maximal display depth* with the ``maxdisplay``
|
||||||
|
command.
|
||||||
|
|
||||||
|
``maxdisplay`` <natural>
|
||||||
|
Sets the maximal display depth to the given integer value. A value of 0
|
||||||
|
means there is no maximal display depth. Default is 3.
|
||||||
|
|
||||||
|
``o``, ``out`` <filename> <exp>
|
||||||
|
Evaluate the expression <exp> and store its string representation into a
|
||||||
|
file named <filename>. If the file does not exist, it will be created,
|
||||||
|
otherwise it will be opened for appending.
|
||||||
|
|
||||||
|
``w``, ``where``
|
||||||
|
Display the current execution point.
|
||||||
|
|
||||||
|
``u``, ``up``
|
||||||
|
Go up in the call stack.
|
||||||
|
|
||||||
|
``d``, ``down``
|
||||||
|
Go down in the call stack.
|
||||||
|
|
||||||
|
``stackframe`` [file]
|
||||||
|
Displays the content of the current stack frame in ``stdout`` or
|
||||||
|
appends it to the file, depending on whether a file is given.
|
||||||
|
|
||||||
|
``callstack``
|
||||||
|
Display the entire call stack (but not its content).
|
||||||
|
|
||||||
|
``l``, ``locals``
|
||||||
|
Display the available local variables in the current stack frame.
|
||||||
|
|
||||||
|
``g``, ``globals``
|
||||||
|
Display all the global variables that are available for inspection.
|
||||||
44
doc/filelist.txt
Executable file
44
doc/filelist.txt
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
Short description of Nimrod's modules
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
============== ==========================================================
|
||||||
|
Module Description
|
||||||
|
============== ==========================================================
|
||||||
|
lexbase buffer handling of the lexical analyser
|
||||||
|
scanner lexical analyser
|
||||||
|
|
||||||
|
ast type definitions of the abstract syntax tree (AST) and
|
||||||
|
node constructors
|
||||||
|
astalgo algorithms for containers of AST nodes; converting the
|
||||||
|
AST to YAML; the symbol table
|
||||||
|
trees few algorithms for nodes; this module is less important
|
||||||
|
types module for traversing type graphs; also contain several
|
||||||
|
helpers for dealing with types
|
||||||
|
|
||||||
|
sigmatch contains the matching algorithm that is used for proc
|
||||||
|
calls
|
||||||
|
semexprs contains the semantic checking phase for expressions
|
||||||
|
semstmts contains the semantic checking phase for statements
|
||||||
|
semtypes contains the semantic checking phase for types
|
||||||
|
|
||||||
|
idents implements a general mapping from identifiers to an internal
|
||||||
|
representation (``PIdent``) that is used, so that a simple
|
||||||
|
pointer comparison suffices to say whether two Nimrod
|
||||||
|
identifiers are equivalent
|
||||||
|
|
||||||
|
ropes implements long strings using represented as trees for
|
||||||
|
lazy evaluation; used mainly by the code generators
|
||||||
|
|
||||||
|
ccgobj contains type definitions neeeded for C code generation
|
||||||
|
and some helpers
|
||||||
|
ccgmangl contains the name mangler for converting Nimrod
|
||||||
|
identifiers to their C counterparts
|
||||||
|
ccgutils contains helpers for the C code generator
|
||||||
|
ccgtemps contains the handling of temporary variables for the
|
||||||
|
C code generator
|
||||||
|
ccgtypes the generator for C types
|
||||||
|
ccgstmts the generator for statements
|
||||||
|
ccgexprs the generator for expressions
|
||||||
|
extccomp this module calls the C compiler and linker; interesting
|
||||||
|
if you want to add support for a new C compiler
|
||||||
|
============== ==========================================================
|
||||||
186
doc/grammar.txt
Executable file
186
doc/grammar.txt
Executable file
|
|
@ -0,0 +1,186 @@
|
||||||
|
module ::= ([COMMENT] [SAD] stmt)*
|
||||||
|
|
||||||
|
optComma ::= [ ',' ] [COMMENT] [IND]
|
||||||
|
operator ::= OP0 | OR | XOR | AND | OP3 | OP4 | OP5 | IS | ISNOT | IN | NOTIN
|
||||||
|
| OP6 | DIV | MOD | SHL | SHR | OP7 | NOT
|
||||||
|
|
||||||
|
prefixOperator ::= OP0 | OP3 | OP4 | OP5 | OP6 | OP7 | NOT
|
||||||
|
|
||||||
|
optInd ::= [COMMENT] [IND]
|
||||||
|
|
||||||
|
|
||||||
|
lowestExpr ::= orExpr ( OP0 optInd orExpr )*
|
||||||
|
orExpr ::= andExpr ( OR | XOR optInd andExpr )*
|
||||||
|
andExpr ::= cmpExpr ( AND optInd cmpExpr )*
|
||||||
|
cmpExpr ::= ampExpr ( OP3 | IS | ISNOT | IN | NOTIN optInd ampExpr )*
|
||||||
|
ampExpr ::= plusExpr ( OP4 optInd plusExpr )*
|
||||||
|
plusExpr ::= mulExpr ( OP5 optInd mulExpr )*
|
||||||
|
mulExpr ::= dollarExpr ( OP6 | DIV | MOD | SHL | SHR optInd dollarExpr )*
|
||||||
|
dollarExpr ::= primary ( OP7 optInd primary )*
|
||||||
|
|
||||||
|
namedTypeOrExpr ::=
|
||||||
|
DOTDOT [expr]
|
||||||
|
| expr [EQUALS (expr [DOTDOT expr] | typeDescK | DOTDOT [expr] )
|
||||||
|
| DOTDOT [expr]]
|
||||||
|
| typeDescK
|
||||||
|
|
||||||
|
castExpr ::= CAST BRACKET_LE optInd typeDesc BRACKERT_RI
|
||||||
|
PAR_LE optInd expr PAR_RI
|
||||||
|
addrExpr ::= ADDR PAR_LE optInd expr PAR_RI
|
||||||
|
symbol ::= ACC (KEYWORD | IDENT | operator | PAR_LE PAR_RI
|
||||||
|
| BRACKET_LE BRACKET_RI) ACC | IDENT
|
||||||
|
accExpr ::= KEYWORD | IDENT | operator [DOT KEYWORD | IDENT | operator]
|
||||||
|
paramList
|
||||||
|
primary ::= ( prefixOperator optInd )* ( IDENT | literal | ACC accExpr ACC
|
||||||
|
| castExpr | addrExpr ) (
|
||||||
|
DOT optInd symbol
|
||||||
|
#| CURLY_LE namedTypeDescList CURLY_RI
|
||||||
|
| PAR_LE optInd
|
||||||
|
namedExprList
|
||||||
|
PAR_RI
|
||||||
|
| BRACKET_LE optInd
|
||||||
|
(namedTypeOrExpr optComma)*
|
||||||
|
BRACKET_RI
|
||||||
|
| CIRCUM
|
||||||
|
| pragma )*
|
||||||
|
|
||||||
|
literal ::= INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
|
||||||
|
| FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
|
||||||
|
| STR_LIT | RSTR_LIT | TRIPLESTR_LIT
|
||||||
|
| CHAR_LIT | RCHAR_LIT
|
||||||
|
| NIL
|
||||||
|
| BRACKET_LE optInd (expr [COLON expr] optComma )* BRACKET_RI # []-Constructor
|
||||||
|
| CURLY_LE optInd (expr [DOTDOT expr] optComma )* CURLY_RI # {}-Constructor
|
||||||
|
| PAR_LE optInd (expr [COLON expr] optComma )* PAR_RI # ()-Constructor
|
||||||
|
|
||||||
|
|
||||||
|
exprList ::= ( expr optComma )*
|
||||||
|
|
||||||
|
namedExpr ::= expr [EQUALS expr] # actually this is symbol EQUALS expr|expr
|
||||||
|
namedExprList ::= ( namedExpr optComma )*
|
||||||
|
|
||||||
|
exprOrSlice ::= expr [ DOTDOT expr ]
|
||||||
|
sliceList ::= ( exprOrSlice optComma )+
|
||||||
|
|
||||||
|
anonymousProc ::= LAMBDA paramList [pragma] EQUALS stmt
|
||||||
|
expr ::= lowestExpr
|
||||||
|
| anonymousProc
|
||||||
|
| IF expr COLON expr
|
||||||
|
(ELIF expr COLON expr)*
|
||||||
|
ELSE COLON expr
|
||||||
|
|
||||||
|
namedTypeDesc ::= typeDescK | expr [EQUALS (typeDescK | expr)]
|
||||||
|
namedTypeDescList ::= ( namedTypeDesc optComma )*
|
||||||
|
|
||||||
|
qualifiedIdent ::= symbol [ DOT symbol ]
|
||||||
|
|
||||||
|
typeDescK ::= VAR typeDesc
|
||||||
|
| REF typeDesc
|
||||||
|
| PTR typeDesc
|
||||||
|
| TYPE expr
|
||||||
|
| PROC paramList [pragma]
|
||||||
|
|
||||||
|
typeDesc ::= typeDescK | primary
|
||||||
|
|
||||||
|
optSemicolon ::= [SEMICOLON]
|
||||||
|
|
||||||
|
macroStmt ::= COLON [stmt] (OF [sliceList] COLON stmt
|
||||||
|
| ELIF expr COLON stmt
|
||||||
|
| EXCEPT exceptList COLON stmt )*
|
||||||
|
[ELSE COLON stmt]
|
||||||
|
|
||||||
|
simpleStmt ::= returnStmt
|
||||||
|
| yieldStmt
|
||||||
|
| discardStmt
|
||||||
|
| raiseStmt
|
||||||
|
| breakStmt
|
||||||
|
| continueStmt
|
||||||
|
| pragma
|
||||||
|
| importStmt
|
||||||
|
| fromStmt
|
||||||
|
| includeStmt
|
||||||
|
| exprStmt
|
||||||
|
complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
|
||||||
|
| blockStmt | asmStmt
|
||||||
|
| procDecl | iteratorDecl | macroDecl | templateDecl
|
||||||
|
| constSection | typeSection | whenStmt | varSection
|
||||||
|
|
||||||
|
indPush ::= IND # push
|
||||||
|
stmt ::= simpleStmt [SAD]
|
||||||
|
| indPush (complexStmt | simpleStmt)
|
||||||
|
([SAD] (complexStmt | simpleStmt) )*
|
||||||
|
DED
|
||||||
|
|
||||||
|
exprStmt ::= lowestExpr [EQUALS expr | (expr optComma)* [macroStmt]]
|
||||||
|
returnStmt ::= RETURN [expr]
|
||||||
|
yieldStmt ::= YIELD expr
|
||||||
|
discardStmt ::= DISCARD expr
|
||||||
|
raiseStmt ::= RAISE [expr]
|
||||||
|
breakStmt ::= BREAK [symbol]
|
||||||
|
continueStmt ::= CONTINUE
|
||||||
|
ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
||||||
|
whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
|
||||||
|
caseStmt ::= CASE expr (OF sliceList COLON stmt)*
|
||||||
|
(ELIF expr COLON stmt)*
|
||||||
|
[ELSE COLON stmt]
|
||||||
|
whileStmt ::= WHILE expr COLON stmt
|
||||||
|
forStmt ::= FOR (symbol optComma)+ IN expr [DOTDOT expr] COLON stmt
|
||||||
|
exceptList ::= (qualifiedIdent optComma)*
|
||||||
|
|
||||||
|
tryStmt ::= TRY COLON stmt
|
||||||
|
(EXCEPT exceptList COLON stmt)*
|
||||||
|
[FINALLY COLON stmt]
|
||||||
|
asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
|
||||||
|
blockStmt ::= BLOCK [symbol] COLON stmt
|
||||||
|
importStmt ::= IMPORT ((symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT) [AS symbol] optComma)+
|
||||||
|
includeStmt ::= INCLUDE ((symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT) optComma)+
|
||||||
|
fromStmt ::= FROM (symbol | STR_LIT | RSTR_LIT | TRIPLESTR_LIT) IMPORT (symbol optComma)+
|
||||||
|
|
||||||
|
pragma ::= CURLYDOT_LE (expr [COLON expr] optComma)+ (CURLYDOT_RI | CURLY_RI)
|
||||||
|
|
||||||
|
paramList ::= [PAR_LE ((symbol optComma)+ COLON typeDesc optComma)* PAR_RI] [COLON typeDesc]
|
||||||
|
|
||||||
|
genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
|
||||||
|
|
||||||
|
procDecl ::= PROC symbol ["*"] [genericParams]
|
||||||
|
paramList [pragma]
|
||||||
|
[EQUALS stmt]
|
||||||
|
macroDecl ::= MACRO symbol ["*"] [genericParams] paramList [pragma]
|
||||||
|
[EQUALS stmt]
|
||||||
|
iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]
|
||||||
|
[EQUALS stmt]
|
||||||
|
templateDecl ::= TEMPLATE symbol ["*"] [genericParams] paramList [pragma]
|
||||||
|
[EQUALS stmt]
|
||||||
|
|
||||||
|
colonAndEquals ::= [COLON typeDesc] EQUALS expr
|
||||||
|
|
||||||
|
constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT]
|
||||||
|
| COMMENT
|
||||||
|
constSection ::= CONST indPush constDecl (SAD constDecl)* DED
|
||||||
|
typeDef ::= typeDesc | recordDef | objectDef | enumDef
|
||||||
|
|
||||||
|
recordIdentPart ::=
|
||||||
|
(symbol ["*" | "-"] [pragma] optComma)+ COLON typeDesc [COMMENT | IND COMMENT]
|
||||||
|
|
||||||
|
recordWhen ::= WHEN expr COLON [COMMENT] recordPart
|
||||||
|
(ELIF expr COLON [COMMENT] recordPart)*
|
||||||
|
[ELSE COLON [COMMENT] recordPart]
|
||||||
|
recordCase ::= CASE expr COLON typeDesc [COMMENT]
|
||||||
|
(OF sliceList COLON [COMMENT] recordPart)*
|
||||||
|
[ELSE COLON [COMMENT] recordPart]
|
||||||
|
|
||||||
|
recordPart ::= recordWhen | recordCase | recordIdentPart
|
||||||
|
| indPush recordPart (SAD recordPart)* DED
|
||||||
|
recordDef ::= RECORD [pragma] recordPart
|
||||||
|
|
||||||
|
objectDef ::= OBJECT [pragma] [OF typeDesc] recordPart
|
||||||
|
enumDef ::= ENUM [OF typeDesc] (symbol [EQUALS expr] optComma [COMMENT | IND COMMENT])+
|
||||||
|
|
||||||
|
typeDecl ::= COMMENT
|
||||||
|
| symbol ["*"] [genericParams] [EQUALS typeDef] [COMMENT | IND COMMENT]
|
||||||
|
|
||||||
|
typeSection ::= TYPE indPush typeDecl (SAD typeDecl)* DED
|
||||||
|
|
||||||
|
colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr
|
||||||
|
varPart ::= (symbol ["*" | "-"] [pragma] optComma)+ colonOrEquals [COMMENT | IND COMMENT]
|
||||||
|
varSection ::= VAR (varPart | indPush (COMMENT|varPart) (SAD (COMMENT|varPart))* DED)
|
||||||
1
doc/html/empty.txt
Executable file
1
doc/html/empty.txt
Executable file
|
|
@ -0,0 +1 @@
|
||||||
|
This file keeps several tools from deleting this subdirectory.
|
||||||
575
doc/intern.txt
Executable file
575
doc/intern.txt
Executable file
|
|
@ -0,0 +1,575 @@
|
||||||
|
=========================================
|
||||||
|
Internals of the Nimrod Compiler
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
Directory structure
|
||||||
|
===================
|
||||||
|
|
||||||
|
The Nimrod project's directory structure is:
|
||||||
|
|
||||||
|
============ ==============================================
|
||||||
|
Path Purpose
|
||||||
|
============ ==============================================
|
||||||
|
``bin`` binary files go into here
|
||||||
|
``nim`` Pascal sources of the Nimrod compiler; this
|
||||||
|
should be modified, not the Nimrod version in
|
||||||
|
``rod``!
|
||||||
|
``rod`` Nimrod sources of the Nimrod compiler;
|
||||||
|
automatically generated from the Pascal
|
||||||
|
version
|
||||||
|
``data`` data files that are used for generating source
|
||||||
|
code go into here
|
||||||
|
``doc`` the documentation lives here; it is a bunch of
|
||||||
|
reStructuredText files
|
||||||
|
``dist`` download packages as zip archives go into here
|
||||||
|
``config`` configuration files for Nimrod go into here
|
||||||
|
``lib`` the Nimrod library lives here; ``rod`` depends
|
||||||
|
on it!
|
||||||
|
``web`` website of Nimrod; generated by ``genweb.py``
|
||||||
|
from the ``*.txt`` and ``*.tmpl`` files
|
||||||
|
``koch`` the Koch Build System (written for Nimrod)
|
||||||
|
``obj`` generated ``*.obj`` files go into here
|
||||||
|
============ ==============================================
|
||||||
|
|
||||||
|
|
||||||
|
Bootstrapping the compiler
|
||||||
|
==========================
|
||||||
|
|
||||||
|
The compiler is written in a subset of Pascal with special annotations so
|
||||||
|
that it can be translated to Nimrod code automatically. This conversion is
|
||||||
|
done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod
|
||||||
|
and Free Pascal can compile the Nimrod compiler.
|
||||||
|
|
||||||
|
Requirements for bootstrapping:
|
||||||
|
|
||||||
|
- Free Pascal (I used version 2.2); it may not be needed
|
||||||
|
- Python (should work with 2.4 or higher) and the code generator *cog*
|
||||||
|
(included in this distribution!)
|
||||||
|
|
||||||
|
- C compiler -- one of:
|
||||||
|
|
||||||
|
* win32-lcc
|
||||||
|
* Borland C++ (tested with 5.5)
|
||||||
|
* Microsoft C++
|
||||||
|
* Digital Mars C++
|
||||||
|
* Watcom C++ (currently broken; a fix is welcome!)
|
||||||
|
* GCC
|
||||||
|
* Intel C++
|
||||||
|
* Pelles C
|
||||||
|
* llvm-gcc
|
||||||
|
|
||||||
|
| Compiling the compiler is a simple matter of running:
|
||||||
|
| ``koch.py boot``
|
||||||
|
| Or you can compile by hand, this is not difficult.
|
||||||
|
|
||||||
|
If you want to debug the compiler, use the command::
|
||||||
|
|
||||||
|
koch.py boot --debugger:on
|
||||||
|
|
||||||
|
The ``koch.py`` script is Nimrod's maintainance script: Everything that has
|
||||||
|
been automated is accessible with it. It is a replacement for make and shell
|
||||||
|
scripting with the advantage that it is more portable and is easier to read.
|
||||||
|
|
||||||
|
|
||||||
|
Coding standards
|
||||||
|
================
|
||||||
|
|
||||||
|
The compiler is written in a subset of Pascal with special annotations so
|
||||||
|
that it can be translated to Nimrod code automatically. As a generell rule,
|
||||||
|
Pascal code that does not translate to Nimrod automatically is forbidden.
|
||||||
|
|
||||||
|
|
||||||
|
Porting to new platforms
|
||||||
|
========================
|
||||||
|
|
||||||
|
Porting Nimrod to a new architecture is pretty easy, since C is the most
|
||||||
|
portable programming language (within certain limits) and Nimrod generates
|
||||||
|
C code, porting the code generator is not necessary.
|
||||||
|
|
||||||
|
POSIX-compliant systems on conventional hardware are usually pretty easy to
|
||||||
|
port: Add the platform to ``platform`` (if it is not already listed there),
|
||||||
|
check that the OS, System modules work and recompile Nimrod.
|
||||||
|
|
||||||
|
The only case where things aren't as easy is when the garbage
|
||||||
|
collector needs some assembler tweaking to work. The standard
|
||||||
|
version of the GC uses C's ``setjmp`` function to store all registers
|
||||||
|
on the hardware stack. It may be that the new platform needs to
|
||||||
|
replace this generic code by some assembler code.
|
||||||
|
|
||||||
|
|
||||||
|
Runtime type information
|
||||||
|
========================
|
||||||
|
|
||||||
|
*Runtime type information* (RTTI) is needed for several aspects of the Nimrod
|
||||||
|
programming language:
|
||||||
|
|
||||||
|
Garbage collection
|
||||||
|
The most important reason for RTTI. Generating
|
||||||
|
traversal procedures produces bigger code and is likely to be slower on
|
||||||
|
modern hardware as dynamic procedure binding is hard to predict.
|
||||||
|
|
||||||
|
Complex assignments
|
||||||
|
Sequences and strings are implemented as
|
||||||
|
pointers to resizeable buffers, but Nimrod requires copying for
|
||||||
|
assignments. Apart from RTTI the compiler could generate copy procedures
|
||||||
|
for any type that needs one. However, this would make the code bigger and
|
||||||
|
the RTTI is likely already there for the GC.
|
||||||
|
|
||||||
|
We already knew the type information as a graph in the compiler.
|
||||||
|
Thus we need to serialize this graph as RTTI for C code generation.
|
||||||
|
Look at the files ``lib/typeinfo.nim``, ``lib/hti.nim`` for more information.
|
||||||
|
|
||||||
|
However, generating type information proved to be difficult and the format
|
||||||
|
wastes memory. Variant records make problems too. We use a mix of iterator
|
||||||
|
procedures and constant data structures:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
type
|
||||||
|
TNimTypeSlot {.export.} = record
|
||||||
|
offset: int
|
||||||
|
typ: int
|
||||||
|
name: CString
|
||||||
|
TSlotIterator = proc (obj: pointer, field: int): ptr TNimTypeSlot
|
||||||
|
TNimType {.export.} = record
|
||||||
|
Kind: TNimTypeKind
|
||||||
|
baseType, indexType: int
|
||||||
|
size, len: int
|
||||||
|
slots: TSlotIterator # instead of: ptr array [0..10_000, TNimTypeSlot]
|
||||||
|
|
||||||
|
This is not easy to understand either. Best is to use just the ``rodgen``
|
||||||
|
module and store type information as string constants.
|
||||||
|
|
||||||
|
After thinking I came to the conclusion that this is again premature
|
||||||
|
optimization. We should just construct the type graph at runtime. In the init
|
||||||
|
section new types should be constructed and registered:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
type
|
||||||
|
TSlotTriple = record
|
||||||
|
offset: int
|
||||||
|
typ: PRTL_Type
|
||||||
|
name: Cstring
|
||||||
|
PSlots = ptr TSlots
|
||||||
|
TSlots = record
|
||||||
|
case kind
|
||||||
|
of linear:
|
||||||
|
fields: array [TSlotTriple]
|
||||||
|
of nested:
|
||||||
|
discriminant: TSlotTriple
|
||||||
|
otherSlots: array [discriminant, PSlots]
|
||||||
|
|
||||||
|
TTypeKind = enum ...
|
||||||
|
RTL_Type = record
|
||||||
|
size: int
|
||||||
|
base: PRTL_Type
|
||||||
|
case kind
|
||||||
|
of tyArray, tySequence:
|
||||||
|
elemSize: int
|
||||||
|
of tyRecord, tyObject, tyEnum:
|
||||||
|
slots: PSlots
|
||||||
|
|
||||||
|
|
||||||
|
The Garbage Collector
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
We use the term *cell* here to refer to everything that is traced
|
||||||
|
(sequences, refs, strings).
|
||||||
|
This section describes how the new GC works. The old algorithms
|
||||||
|
all had the same problem: Too complex to get them right. This one
|
||||||
|
tries to find the right compromise.
|
||||||
|
|
||||||
|
The basic algorithm is *Deferrent reference counting* with cycle detection.
|
||||||
|
References in the stack are not counted for better performance and easier C
|
||||||
|
code generation. The GC starts by traversing the hardware stack and increments
|
||||||
|
the reference count (RC) of every cell that it encounters. After the GC has
|
||||||
|
done its work the stack is traversed again and the RC of every cell
|
||||||
|
that it encounters are decremented again. Thus no marking bits in the RC are
|
||||||
|
needed. Between these stack traversals the GC has a complete accurate view over
|
||||||
|
the RCs.
|
||||||
|
|
||||||
|
Each cell has a header consisting of a RC and a pointer to its type
|
||||||
|
descriptor. However the program does not know about these, so they are placed at
|
||||||
|
negative offsets. In the GC code the type ``PCell`` denotes a pointer
|
||||||
|
decremented by the right offset, so that the header can be accessed easily. It
|
||||||
|
is extremely important that ``pointer`` is not confused with a ``PCell``
|
||||||
|
as this would lead to a memory corruption.
|
||||||
|
|
||||||
|
|
||||||
|
When to trigger a collection
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Since there are really two different garbage collectors (reference counting
|
||||||
|
and mark and sweep) we use two different heuristics when to run the passes.
|
||||||
|
The RC-GC pass is fairly cheap: Thus we use an additive increase (7 pages)
|
||||||
|
for the RC_Threshold and a multiple increase for the CycleThreshold.
|
||||||
|
|
||||||
|
|
||||||
|
The AT and ZCT sets
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The GC maintains two sets throughout the lifetime of
|
||||||
|
the program (plus two temporary ones). The AT (*any table*) simply contains
|
||||||
|
every cell. The ZCT (*zero count table*) contains every cell whose RC is
|
||||||
|
zero. This is used to reclaim most cells fast.
|
||||||
|
|
||||||
|
The ZCT contains redundant information -- the AT alone would suffice.
|
||||||
|
However, traversing the AT and look if the RC is zero would touch every living
|
||||||
|
cell in the heap! That's why the ZCT is updated whenever a RC drops to zero.
|
||||||
|
The ZCT is not updated when a RC is incremented from zero to one, as
|
||||||
|
this would be too costly.
|
||||||
|
|
||||||
|
|
||||||
|
The CellSet data structure
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The AT and ZCT depend on an extremely efficient datastructure for storing a
|
||||||
|
set of pointers - this is called a ``PCellSet`` in the source code.
|
||||||
|
Inserting, deleting and searching are done in constant time. However,
|
||||||
|
modifying a ``PCellSet`` during traversation leads to undefined behaviour.
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
type
|
||||||
|
PCellSet # hidden
|
||||||
|
|
||||||
|
proc allocCellSet: PCellSet # make a new set
|
||||||
|
proc deallocCellSet(s: PCellSet) # empty the set and free its memory
|
||||||
|
proc incl(s: PCellSet, elem: PCell) # include an element
|
||||||
|
proc excl(s: PCellSet, elem: PCell) # exclude an element
|
||||||
|
|
||||||
|
proc `in`(elem: PCell, s: PCellSet): bool
|
||||||
|
|
||||||
|
iterator elements(s: PCellSet): (elem: PCell)
|
||||||
|
|
||||||
|
|
||||||
|
All the operations have to be performed efficiently. Because a Cellset can
|
||||||
|
become huge (the AT contains every allocated cell!) a hash table is not
|
||||||
|
suitable for this.
|
||||||
|
|
||||||
|
We use a mixture of bitset and patricia tree for this. One node in the
|
||||||
|
patricia tree contains a bitset that decribes a page of the operating system
|
||||||
|
(not always, but that doesn't matter).
|
||||||
|
So including a cell is done as follows:
|
||||||
|
|
||||||
|
- Find the page descriptor for the page the cell belongs to.
|
||||||
|
- Set the appropriate bit in the page descriptor indicating that the
|
||||||
|
cell points to the start of a memory block.
|
||||||
|
|
||||||
|
Removing a cell is analogous - the bit has to be set to zero.
|
||||||
|
Single page descriptors are never deleted from the tree. Typically a page
|
||||||
|
descriptor is only 19 words big, so it does not waste much by not deleting
|
||||||
|
it. Apart from that the AT and ZCT are rebuilt frequently, so removing a
|
||||||
|
single page descriptor from the tree is never necessary.
|
||||||
|
|
||||||
|
Complete traversal is done like so::
|
||||||
|
|
||||||
|
for each page decriptor d:
|
||||||
|
for each bit in d:
|
||||||
|
if bit == 1:
|
||||||
|
traverse the pointer belonging to this bit
|
||||||
|
|
||||||
|
|
||||||
|
Further complications
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
In Nimrod the compiler cannot always know if a reference
|
||||||
|
is stored on the stack or not. This is caused by var parameters.
|
||||||
|
Consider this example:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
proc setRef(r: var ref TNode) =
|
||||||
|
new(r)
|
||||||
|
|
||||||
|
proc usage =
|
||||||
|
var
|
||||||
|
r: ref TNode
|
||||||
|
setRef(r) # here we should not update the reference counts, because
|
||||||
|
# r is on the stack
|
||||||
|
setRef(r.left) # here we should update the refcounts!
|
||||||
|
|
||||||
|
Though it would be possible to produce code updating the refcounts (if
|
||||||
|
necessary) before and after the call to ``setRef``, it is a complex task to
|
||||||
|
do so in the code generator. So we don't and instead decide at runtime
|
||||||
|
whether the reference is on the stack or not. The generated code looks
|
||||||
|
roughly like this:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
void setref(TNode** ref) {
|
||||||
|
unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode)))
|
||||||
|
}
|
||||||
|
void usage(void) {
|
||||||
|
setRef(&r)
|
||||||
|
setRef(&r->left)
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that for systems with a continous stack (which most systems have)
|
||||||
|
the check whether the ref is on the stack is very cheap (only two
|
||||||
|
comparisons). Another advantage of this scheme is that the code produced is
|
||||||
|
a tiny bit smaller.
|
||||||
|
|
||||||
|
|
||||||
|
The algorithm in pseudo-code
|
||||||
|
----------------------------
|
||||||
|
Now we come to the nitty-gritty. The algorithm works in several phases.
|
||||||
|
|
||||||
|
Phase 1 - Consider references from stack
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
::
|
||||||
|
|
||||||
|
for each pointer p in the stack: incRef(p)
|
||||||
|
|
||||||
|
This is necessary because references in the hardware stack are not traced for
|
||||||
|
better performance. After Phase 1 the RCs are accurate.
|
||||||
|
|
||||||
|
|
||||||
|
Phase 2 - Free the ZCT
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
This is how things used to (not) work::
|
||||||
|
|
||||||
|
for p in elements(ZCT):
|
||||||
|
if RC(p) == 0:
|
||||||
|
call finalizer of p
|
||||||
|
for c in children(p): decRef(c) # free its children recursively
|
||||||
|
# if necessary; the childrens RC >= 1, BUT they may still be in the ZCT!
|
||||||
|
free(p)
|
||||||
|
else:
|
||||||
|
remove p from the ZCT
|
||||||
|
|
||||||
|
Instead we do it this way. Note that the recursion is gone too!
|
||||||
|
::
|
||||||
|
|
||||||
|
newZCT = nil
|
||||||
|
for p in elements(ZCT):
|
||||||
|
if RC(p) == 0:
|
||||||
|
call finalizer of p
|
||||||
|
for c in children(p):
|
||||||
|
assert(RC(c) > 0)
|
||||||
|
dec(RC(c))
|
||||||
|
if RC(c) == 0:
|
||||||
|
if newZCT == nil: newZCT = allocCellSet()
|
||||||
|
incl(newZCT, c)
|
||||||
|
free(p)
|
||||||
|
else:
|
||||||
|
# nothing to do! We will use the newZCS
|
||||||
|
|
||||||
|
deallocCellSet(ZCT)
|
||||||
|
ZCT = newZCT
|
||||||
|
|
||||||
|
This phase is repeated until enough memory is available or the ZCT is nil.
|
||||||
|
If still not enough memory is available the cyclic detector gets its chance
|
||||||
|
to do something.
|
||||||
|
|
||||||
|
|
||||||
|
Phase 3 - Cycle detection
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Cycle detection works by subtracting internal reference counts::
|
||||||
|
|
||||||
|
newAT = allocCellSet()
|
||||||
|
|
||||||
|
for y in elements(AT):
|
||||||
|
# pretend that y is dead:
|
||||||
|
for c in children(y):
|
||||||
|
dec(RC(c))
|
||||||
|
# note that this should not be done recursively as we have all needed
|
||||||
|
# pointers in the AT! This makes it more efficient too!
|
||||||
|
|
||||||
|
proc restore(y: PCell) =
|
||||||
|
# unfortunately, the recursion here cannot be eliminated easily
|
||||||
|
if y not_in newAT:
|
||||||
|
incl(newAT, y)
|
||||||
|
for c in children(y):
|
||||||
|
inc(RC(c)) # restore proper reference counts!
|
||||||
|
restore(c)
|
||||||
|
|
||||||
|
for y in elements(AT) with rc > 0:
|
||||||
|
restore(y)
|
||||||
|
|
||||||
|
for y in elements(AT) with rc == 0:
|
||||||
|
free(y) # if pretending worked, it was part of a cycle
|
||||||
|
|
||||||
|
AT = newAT
|
||||||
|
|
||||||
|
|
||||||
|
Phase 4 - Ignore references from stack again
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
::
|
||||||
|
|
||||||
|
for each pointer p in the stack:
|
||||||
|
dec(RC(p))
|
||||||
|
if RC(p) == 0: incl(ZCT, p)
|
||||||
|
|
||||||
|
Now the RCs correctly discard any references from the stack. One can also see
|
||||||
|
this as a temporary marking operation. Things that are referenced from stack
|
||||||
|
are marked during the GC's operarion and now have to be unmarked.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The compiler's architecture
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Nimrod uses the classic compiler architecture: A scanner feds tokens to a
|
||||||
|
parser. The parser builds a syntax tree that is used by the code generator.
|
||||||
|
This syntax tree is the interface between the parser and the code generator.
|
||||||
|
It is essential to understand most of the compiler's code.
|
||||||
|
|
||||||
|
In order to compile Nimrod correctly, type-checking has to be seperated from
|
||||||
|
parsing. Otherwise generics would not work. Code generation is done for a
|
||||||
|
whole module only after it has been checked for semantics.
|
||||||
|
|
||||||
|
.. include:: filelist.txt
|
||||||
|
|
||||||
|
The first command line argument selects the backend. Thus the backend is
|
||||||
|
responsible for calling the parser and semantic checker. However, when
|
||||||
|
compiling ``import`` or ``include`` statements, the semantic checker needs to
|
||||||
|
call the backend, this is done by embedding a PBackend into a TContext.
|
||||||
|
|
||||||
|
|
||||||
|
The syntax tree
|
||||||
|
---------------
|
||||||
|
The synax tree consists of nodes which may have an arbitrary number of
|
||||||
|
children. Types and symbols are represented by other nodes, because they
|
||||||
|
may contain cycles. The AST changes its shape after semantic checking. This
|
||||||
|
is needed to make life easier for the code generators. See the "ast" module
|
||||||
|
for the type definitions.
|
||||||
|
|
||||||
|
We use the notation ``nodeKind(fields, [sons])`` for describing
|
||||||
|
nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``.
|
||||||
|
XXX: Description of the language's syntax and the corresponding trees.
|
||||||
|
|
||||||
|
|
||||||
|
How the RTL is compiled
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The system module contains the part of the RTL which needs support by
|
||||||
|
compiler magic (and the stuff that needs to be in it because the spec
|
||||||
|
says so). The C code generator generates the C code for it just like any other
|
||||||
|
module. However, calls to some procedures like ``addInt`` are inserted by
|
||||||
|
the CCG. Therefore the module ``magicsys`` contains a table
|
||||||
|
(``compilerprocs``) with all symbols that are marked as ``compilerproc``.
|
||||||
|
|
||||||
|
|
||||||
|
How separate compilation will work
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Soon compiling from scratch every module that's needed will become too slow as
|
||||||
|
programs grow. For easier cleaning all generated files are generated in the
|
||||||
|
directory: ``$base/rod_gen``. This cannot be changed. The generated C files
|
||||||
|
get the names of the modules they result from. A compiled Nimrod module has the
|
||||||
|
extension ``.rod`` and is a binary file. The format may change from release
|
||||||
|
to release. The rod-file is mostly a binary representation of the parse trees.
|
||||||
|
|
||||||
|
Nimrod currently compiles any module into its own C file. Some things like
|
||||||
|
type-information, common string literals, common constant sets need to be
|
||||||
|
shared though. We deal with this problem by writing the shared data
|
||||||
|
in the main C file. Only "headers" are generated in the other modules. However,
|
||||||
|
each precompiled Nimrod module lists the shared data it depends on. The same
|
||||||
|
holds for procedures that have to generated from generics.
|
||||||
|
|
||||||
|
A big problem is that the data must get the same name each time it is compiled.
|
||||||
|
|
||||||
|
The C compiler is only called for the C files, that changed after the last
|
||||||
|
compilation (or if their object file does not exist anymore). To work
|
||||||
|
reliably, in the header comment of the C file these things are listed, so
|
||||||
|
that the C compiler is called again should they change:
|
||||||
|
|
||||||
|
* Nimrod's Version
|
||||||
|
* the target CC
|
||||||
|
* the target OS
|
||||||
|
* the target CPU
|
||||||
|
|
||||||
|
The version is questionable: If the resulting C file is the same, it does not
|
||||||
|
matter that Nimrods's version has increased. We do it anyway to be on the safe
|
||||||
|
side.
|
||||||
|
|
||||||
|
|
||||||
|
Generation of dynamic link libraries
|
||||||
|
====================================
|
||||||
|
|
||||||
|
Generation of dynamic link libraries or shared libraries is not difficult; the
|
||||||
|
underlying C compiler already does all the hard work for us. The problem is the
|
||||||
|
common runtime library, especially the memory manager. Note that Borland's
|
||||||
|
Delphi had exactly the same problem. The workaround is to not link the GC with
|
||||||
|
the Dll and provide an extra runtime dll that needs to be initialized.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
How to implement closures
|
||||||
|
=========================
|
||||||
|
|
||||||
|
A closure is a record of a proc pointer and a context ref. The context ref
|
||||||
|
points to a garbage collected record that contains the needed variables.
|
||||||
|
An example:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
|
||||||
|
type
|
||||||
|
TListRec = record
|
||||||
|
data: string
|
||||||
|
next: ref TListRec
|
||||||
|
|
||||||
|
proc forEach(head: ref TListRec, visitor: proc (s: string) {.closure.}) =
|
||||||
|
var it = head
|
||||||
|
while it != nil:
|
||||||
|
visit(it.data)
|
||||||
|
it = it.next
|
||||||
|
|
||||||
|
proc sayHello() =
|
||||||
|
var L = new List(["hallo", "Andreas"])
|
||||||
|
var temp = "jup\xff"
|
||||||
|
forEach(L, lambda(s: string) =
|
||||||
|
io.write(temp)
|
||||||
|
io.write(s)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
This should become the following in C:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
typedef struct ... /* List type */
|
||||||
|
|
||||||
|
typedef struct closure {
|
||||||
|
void (*PrcPart)(string, void*);
|
||||||
|
void* ClPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Tcl_data {
|
||||||
|
string temp; // all accessed variables are put in here!
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEach(TListRec* head, const closure visitor) {
|
||||||
|
TListRec* it = head;
|
||||||
|
while (it != NIM_NULL) {
|
||||||
|
visitor.prc(it->data, visitor->cl_data);
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStr(string s, void* cl_data) {
|
||||||
|
Tcl_data* x = (Tcl_data*) cl_data;
|
||||||
|
io_write(x->temp);
|
||||||
|
io_write(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sayhello() {
|
||||||
|
Tcl_data* data = new(...);
|
||||||
|
asgnRef(&data->temp, "jup\xff");
|
||||||
|
...
|
||||||
|
|
||||||
|
closure cl;
|
||||||
|
cl.prc = printStr;
|
||||||
|
cl.cl_data = data;
|
||||||
|
foreach(L, cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
What about nested closure? - There's not much difference: Just put all used
|
||||||
|
variables in the data record.
|
||||||
48
doc/lib.txt
Executable file
48
doc/lib.txt
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
=======================
|
||||||
|
Nimrod Standard Library
|
||||||
|
=======================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
Though the Nimrod Standard Library is still evolving, it is already quite
|
||||||
|
usable. It is divided into basic libraries that contains modules that virtually
|
||||||
|
every program will need and advanced libraries which are more heavy weight.
|
||||||
|
Advanced libraries are in the ``lib/base`` directory.
|
||||||
|
|
||||||
|
Basic libraries
|
||||||
|
===============
|
||||||
|
|
||||||
|
* `System <system.html>`_
|
||||||
|
Basic procs and operators that every program needs. It also provides IO
|
||||||
|
facilities for reading and writing text and binary files. It is imported
|
||||||
|
implicitly by the compiler. Do not import it directly. It relies on compiler
|
||||||
|
magic to work.
|
||||||
|
|
||||||
|
* `Strutils <strutils.html>`_
|
||||||
|
This module contains common string handling operations like converting a
|
||||||
|
string into uppercase, splitting a string into substrings, searching for
|
||||||
|
substrings, replacing substrings.
|
||||||
|
|
||||||
|
* `OS <os.html>`_
|
||||||
|
Basic operating system facilities like retrieving environment variables,
|
||||||
|
reading command line arguments, working with directories, running shell
|
||||||
|
commands, etc. This module is -- like any other basic library --
|
||||||
|
platform independant.
|
||||||
|
|
||||||
|
* `Math <math.html>`_
|
||||||
|
Mathematical operations like cosine, square root.
|
||||||
|
|
||||||
|
* `Complex <complex.html>`_
|
||||||
|
This module implements complex numbers and their mathematical operations.
|
||||||
|
|
||||||
|
* `Times <times.html>`_
|
||||||
|
The ``times`` module contains basic support for working with time.
|
||||||
|
|
||||||
|
|
||||||
|
Advanced libaries
|
||||||
|
=================
|
||||||
|
|
||||||
|
* `Regexprs <regexprs.html>`_
|
||||||
|
This module contains procedures and operators for handling regular
|
||||||
|
expressions.
|
||||||
1742
doc/manual.txt
Executable file
1742
doc/manual.txt
Executable file
File diff suppressed because it is too large
Load diff
295
doc/nimdoc.css
Executable file
295
doc/nimdoc.css
Executable file
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
:Author: David Goodger
|
||||||
|
:Contact: goodger@python.org
|
||||||
|
:Date: $Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006) $
|
||||||
|
:Revision: $Revision: 4564 $
|
||||||
|
:Copyright: This stylesheet has been placed in the public domain.
|
||||||
|
|
||||||
|
Default cascading style sheet for the HTML output of Docutils.
|
||||||
|
|
||||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||||
|
customize this style sheet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Modified for the Nimrod Documenation by
|
||||||
|
Andreas Rumpf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* used to remove borders from tables and images */
|
||||||
|
.borderless, table.borderless td, table.borderless th {
|
||||||
|
border: 0 }
|
||||||
|
|
||||||
|
table.borderless td, table.borderless th {
|
||||||
|
/* Override padding for "table.docutils td" with "! important".
|
||||||
|
The right padding separates the table cells. */
|
||||||
|
padding: 0 0.5em 0 0 ! important }
|
||||||
|
|
||||||
|
.first {
|
||||||
|
/* Override more specific margin styles with "! important". */
|
||||||
|
margin-top: 0 ! important }
|
||||||
|
|
||||||
|
.last, .with-subtitle {
|
||||||
|
margin-bottom: 0 ! important }
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none }
|
||||||
|
|
||||||
|
a.toc-backref {
|
||||||
|
text-decoration: none ;
|
||||||
|
color: black }
|
||||||
|
|
||||||
|
blockquote.epigraph {
|
||||||
|
margin: 2em 5em ; }
|
||||||
|
|
||||||
|
dl.docutils dd {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||||
|
dl.docutils dt {
|
||||||
|
font-weight: bold }
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.abstract {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
div.abstract p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||||
|
div.hint, div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||||
|
div.important p.admonition-title, div.note p.admonition-title,
|
||||||
|
div.tip p.admonition-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||||
|
compound paragraphs.
|
||||||
|
div.compound .compound-first, div.compound .compound-middle {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.compound .compound-last, div.compound .compound-middle {
|
||||||
|
margin-top: 0.5em }
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.dedication {
|
||||||
|
margin: 2em 5em ;
|
||||||
|
text-align: center ;
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
div.dedication p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-style: normal }
|
||||||
|
|
||||||
|
div.figure {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em }
|
||||||
|
|
||||||
|
div.footer, div.header {
|
||||||
|
clear: both;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
div.line-block {
|
||||||
|
display: block ;
|
||||||
|
margin-top: 1em ;
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
div.line-block div.line-block {
|
||||||
|
margin-top: 0 ;
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-left: 1.5em }
|
||||||
|
|
||||||
|
div.sidebar {
|
||||||
|
margin-left: 1em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em ;
|
||||||
|
background-color: #ffffee ;
|
||||||
|
width: 40% ;
|
||||||
|
float: right ;
|
||||||
|
clear: right }
|
||||||
|
|
||||||
|
div.sidebar p.rubric {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-size: medium }
|
||||||
|
|
||||||
|
div.system-messages {
|
||||||
|
margin: 5em }
|
||||||
|
|
||||||
|
div.system-messages h1 {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
div.system-message {
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.system-message p.system-message-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
margin: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||||
|
margin-top: 0.4em }
|
||||||
|
|
||||||
|
h1.title { text-align: center }
|
||||||
|
h2.subtitle { text-align: center }
|
||||||
|
hr.docutils { width: 75% }
|
||||||
|
img.align-left { clear: left }
|
||||||
|
img.align-right { clear: right }
|
||||||
|
|
||||||
|
ol.simple, ul.simple {
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal }
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha }
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha }
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman }
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman }
|
||||||
|
|
||||||
|
p.attribution {
|
||||||
|
text-align: right ;
|
||||||
|
margin-left: 50% }
|
||||||
|
|
||||||
|
p.caption {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
p.credits {
|
||||||
|
font-style: italic ;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
p.label {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
p.rubric {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger ;
|
||||||
|
color: maroon ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
p.sidebar-title {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger }
|
||||||
|
|
||||||
|
p.sidebar-subtitle {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
pre.address {
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-top: 0 ;
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre, span.pre {
|
||||||
|
background-color:#F9F9F9;
|
||||||
|
border:1px dotted #2F6FAB;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {padding:1em;}
|
||||||
|
|
||||||
|
pre.literal-block, pre.doctest-block {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em }
|
||||||
|
|
||||||
|
span.classifier {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-style: oblique }
|
||||||
|
|
||||||
|
span.classifier-delimiter {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
span.interpreted {
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
span.option {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
span.pre { white-space: pre }
|
||||||
|
|
||||||
|
span.problematic {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
span.section-subtitle {
|
||||||
|
/* font-size relative to parent (h1..h6 element) */
|
||||||
|
font-size: 80% }
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid 1px gray;
|
||||||
|
margin-left: 1px }
|
||||||
|
|
||||||
|
table.docinfo {
|
||||||
|
margin: 2em 4em }
|
||||||
|
|
||||||
|
table.docutils {
|
||||||
|
margin-top: 0.5em ;
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
table.footnote {
|
||||||
|
border-left: solid 1px black;
|
||||||
|
margin-left: 1px }
|
||||||
|
|
||||||
|
table.docutils td, table.docutils th,
|
||||||
|
table.docinfo td, table.docinfo th {
|
||||||
|
padding-left: 0.5em ;
|
||||||
|
padding-right: 0.5em ;
|
||||||
|
vertical-align: top }
|
||||||
|
|
||||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: left ;
|
||||||
|
white-space: nowrap ;
|
||||||
|
padding-left: 0 }
|
||||||
|
|
||||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
ul.auto-toc {
|
||||||
|
list-style-type: none }
|
||||||
|
|
||||||
|
a.reference {
|
||||||
|
color: #E00000;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.reference:hover {
|
||||||
|
color: #E00000;
|
||||||
|
background-color: #ffff00;
|
||||||
|
display: margin;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.topic ul {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
241
doc/nimrodc.txt
Executable file
241
doc/nimrodc.txt
Executable file
|
|
@ -0,0 +1,241 @@
|
||||||
|
===================================
|
||||||
|
Nimrod Compiler User Guide
|
||||||
|
===================================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document describes the usage of the *Nimrod compiler*
|
||||||
|
on the different supported platforms. It is not a definition of the Nimrod
|
||||||
|
programming system (therefore is the Nimrod manual).
|
||||||
|
|
||||||
|
Nimrod is free software; it is licensed under the
|
||||||
|
`GNU General Public License <gpl.html>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Compiler Usage
|
||||||
|
==============
|
||||||
|
|
||||||
|
Command line switches
|
||||||
|
---------------------
|
||||||
|
Basis command line switches are:
|
||||||
|
|
||||||
|
.. include:: ../data/basicopt.txt
|
||||||
|
|
||||||
|
Advanced command line switches are:
|
||||||
|
|
||||||
|
.. include:: ../data/advopt.txt
|
||||||
|
|
||||||
|
|
||||||
|
Configuration file
|
||||||
|
------------------
|
||||||
|
The ``nimrod`` executable loads the configuration file ``config/nimrod.cfg``
|
||||||
|
unless this is suppressed by the ``--skip_cfg`` command line option.
|
||||||
|
Configuration settings can be overwritten in a project specific
|
||||||
|
configuration file that is read automatically. This specific file has to
|
||||||
|
be in the same directory as the project and be of the same name, except
|
||||||
|
that its extension should be ``.cfg``.
|
||||||
|
|
||||||
|
Command line settings have priority over configuration file settings.
|
||||||
|
|
||||||
|
|
||||||
|
Nimrod's directory structure
|
||||||
|
----------------------------
|
||||||
|
The generated files that Nimrod produces all go into a subdirectory called
|
||||||
|
``rod_gen``. This makes it easy to write a script that deletes all generated
|
||||||
|
files. For example the generated C code for the module ``path/modA.nim``
|
||||||
|
will become ``path/rod_gen/modA.c``.
|
||||||
|
|
||||||
|
However, the generated C code is not platform independant! C code generated for
|
||||||
|
Linux does not compile on Windows, for instance. The comment on top of the
|
||||||
|
C file lists the OS, CPU and CC the file has been compiled for.
|
||||||
|
|
||||||
|
The library lies in ``lib``. Directly in the library directory are essential
|
||||||
|
Nimrod modules like the ``system`` and ``os`` modules. Under ``lib/base``
|
||||||
|
are additional specialized libraries or interfaces to foreign libraries which
|
||||||
|
are included in the standard distribution. The ``lib/extra`` directory is
|
||||||
|
initially empty. Third party libraries should go there. In the default
|
||||||
|
configuration the compiler always searches for libraries in ``lib``,
|
||||||
|
``lib/base`` and ``lib/extra``.
|
||||||
|
|
||||||
|
|
||||||
|
Additional Features
|
||||||
|
===================
|
||||||
|
|
||||||
|
This section describes Nimrod's additional features that are not listed in the
|
||||||
|
Nimrod manual.
|
||||||
|
|
||||||
|
New Pragmas and Options
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Because Nimrod generates C code it needs some "red tape" to work properly.
|
||||||
|
Thus lots of options and pragmas for tweaking the generated C code are
|
||||||
|
available.
|
||||||
|
|
||||||
|
No_decl Pragma
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
The `no_decl`:idx: pragma can be applied to almost any symbol (variable, proc,
|
||||||
|
type, etc.) and is one of the most important for interoperability with C:
|
||||||
|
It tells Nimrod that it should not generate a declaration for the symbol in
|
||||||
|
the C code. Thus it makes the following possible, for example:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var
|
||||||
|
EOF {.import: "EOF", no_decl.}: cint # pretend EOF was a variable, as
|
||||||
|
# Nimrod does not know its value
|
||||||
|
|
||||||
|
Varargs Pragma
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
The `varargs`:idx: pragma can be applied to procedures only. It tells Nimrod
|
||||||
|
that the proc can take a variable number of parameters after the last
|
||||||
|
specified parameter. Nimrod string values will be converted to C
|
||||||
|
strings automatically:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
proc printf(formatstr: cstring) {.nodecl, varargs.}
|
||||||
|
|
||||||
|
printf("hallo %s", "world") # "world" will be passed as C string
|
||||||
|
|
||||||
|
|
||||||
|
Header Pragma
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
The `header`:idx: pragma is very similar to the ``no_decl`` pragma: It can be
|
||||||
|
applied to almost any symbol and specifies that not only it should not be
|
||||||
|
declared but also that it leads to the inclusion of a given header file:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
type
|
||||||
|
PFile {.import: "FILE*", header: "<stdio.h>".} = pointer
|
||||||
|
# import C's FILE* type; Nimrod will treat it as a new pointer type
|
||||||
|
|
||||||
|
The ``header`` pragma expects always a string constant. The string contant
|
||||||
|
contains the header file: As usual for C, a system header file is enclosed
|
||||||
|
in angle brackets: ``<>``. If no angle brackets are given, Nimrod
|
||||||
|
encloses the header file in ``""`` in the generated C code.
|
||||||
|
|
||||||
|
|
||||||
|
No_static Pragma
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
The `no_static`:idx: pragma can be applied to almost any symbol and specifies
|
||||||
|
that it shall not be declared ``static`` in the generated C code. Note that
|
||||||
|
symbols in the interface part of a module never get declared ``static``, so
|
||||||
|
only in special cases is this pragma necessary.
|
||||||
|
|
||||||
|
|
||||||
|
Line_dir Option
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The `line_dir`:idx: option can be turned on or off. If on the generated C code
|
||||||
|
contains ``#line`` directives.
|
||||||
|
|
||||||
|
|
||||||
|
Stack_trace Option
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
If the `stack_trace`:idx: option is turned on, the generated C contains code to
|
||||||
|
ensure that proper stack traces are given if the program crashes or an
|
||||||
|
uncaught exception is raised.
|
||||||
|
|
||||||
|
|
||||||
|
Line_trace Option
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
The `line_trace`:idx: option implies the ``stack_trace`` option. If turned on,
|
||||||
|
the generated C contains code to ensure that proper stack traces with line
|
||||||
|
number information are given if the program crashes or an uncaught exception
|
||||||
|
is raised.
|
||||||
|
|
||||||
|
Debugger Option
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The `debugger`:idx: option enables or disables the *Embedded Nimrod Debugger*.
|
||||||
|
See the documentation of endb_ for further information.
|
||||||
|
|
||||||
|
|
||||||
|
Breakpoint Pragma
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
The *breakpoint* pragma was specially added for the sake of debugging with
|
||||||
|
ENDB. See the documentation of `endb <endb.html>`_ for further information.
|
||||||
|
|
||||||
|
|
||||||
|
Volatile Pragma
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The `volatile`:idx: pragma is for variables only. It declares the variable as
|
||||||
|
``volatile``, whatever that means in C/C++.
|
||||||
|
|
||||||
|
Register Pragma
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The `register`:idx: pragma is for variables only. It declares the variable as
|
||||||
|
``register``, giving the compiler a hint that the variable should be placed
|
||||||
|
in a hardware register for faster access. C compilers usually ignore this
|
||||||
|
though and for good reason: Often they do a better job without it anyway.
|
||||||
|
|
||||||
|
In highly specific cases (a dispatch loop of interpreters for example) it
|
||||||
|
may provide benefits, though.
|
||||||
|
|
||||||
|
|
||||||
|
Disabling certain messages
|
||||||
|
--------------------------
|
||||||
|
Nimrod generates some warnings and hints ("line too long") that may annoy the
|
||||||
|
user. Thus a mechanism for disabling certain messages is provided: Each hint
|
||||||
|
and warning message contains a symbol in brackets. This is the message's
|
||||||
|
identifier that can be used to enable or disable it:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
{.warning[LineTooLong]: off.} # turn off warning about too long lines
|
||||||
|
|
||||||
|
This is often better than disabling all warnings at once.
|
||||||
|
|
||||||
|
|
||||||
|
Debugging with Nimrod
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Nimrod comes with its own *Embedded Nimrod Debugger*. See
|
||||||
|
the documentation of endb_ for further information.
|
||||||
|
|
||||||
|
|
||||||
|
Optimizing for Nimrod
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Nimrod has no separate optimizer, but the C code that is produced is very
|
||||||
|
efficient. Most C compilers have excellent optimizers, so usually it is
|
||||||
|
not needed to optimize one's code. Nimrod has been designed to encourage
|
||||||
|
efficient code: The most readable code in Nimrod is often the most efficient
|
||||||
|
too.
|
||||||
|
|
||||||
|
However, sometimes one has to optimize. Do it in the following order:
|
||||||
|
|
||||||
|
1. switch off the embedded debugger (it is **slow**!)
|
||||||
|
2. turn on the optimizer and turn off runtime checks
|
||||||
|
3. profile your code to find where the bottlenecks are
|
||||||
|
4. try to find a better algorithm
|
||||||
|
5. do low-level optimizations
|
||||||
|
|
||||||
|
This section can only help you with the last item. Note that rewriting parts
|
||||||
|
of your program in C is *never* necessary to speed up your program, because
|
||||||
|
everything that can be done in C can be done in Nimrod. Rewriting parts in
|
||||||
|
assembler *might*.
|
||||||
|
|
||||||
|
Optimizing string handling
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
String assignments are sometimes expensive in Nimrod: They are required to
|
||||||
|
copy the whole string. However, the compiler is often smart enough to not copy
|
||||||
|
strings. Due to the argument passing semantics, strings are never copied when
|
||||||
|
passed to subroutines. The compiler does not copy strings that are returned by
|
||||||
|
a routine, because a routine returns a new string anyway. Thus it is efficient
|
||||||
|
to do:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var s = procA() # assignment will not copy the string; procA allocates a new
|
||||||
|
# string anyway
|
||||||
|
|
||||||
|
However it is not efficient to do:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var s = varA # assignment has to copy the whole string into a new buffer!
|
||||||
|
|
||||||
|
String case statements are optimized too. A hashing scheme is used for them
|
||||||
|
if several different string constants are used. This is likely to be more
|
||||||
|
efficient than any hand-coded scheme.
|
||||||
9
doc/overview.txt
Executable file
9
doc/overview.txt
Executable file
|
|
@ -0,0 +1,9 @@
|
||||||
|
=============================
|
||||||
|
Nimrod Documentation Overview
|
||||||
|
=============================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. include:: ../doc/docs.txt
|
||||||
|
|
||||||
220
doc/posix.txt
Executable file
220
doc/posix.txt
Executable file
|
|
@ -0,0 +1,220 @@
|
||||||
|
Function POSIX Description
|
||||||
|
access Tests for file accessibility
|
||||||
|
alarm Schedules an alarm
|
||||||
|
asctime Converts a time structure to a string
|
||||||
|
cfgetispeed Reads terminal input baud rate
|
||||||
|
cfgetospeed Reads terminal output baud rate
|
||||||
|
cfsetispeed Sets terminal input baud rate
|
||||||
|
cfsetospeed Sets terminal output baud rate
|
||||||
|
chdir Changes current working directory
|
||||||
|
chmod Changes file mode
|
||||||
|
chown Changes owner and/or group of a file
|
||||||
|
close Closes a file
|
||||||
|
closedir Ends directory read operation
|
||||||
|
creat Creates a new file or rewrites an existing one
|
||||||
|
ctermid Generates terminal pathname
|
||||||
|
cuserid Gets user name
|
||||||
|
dup Duplicates an open file descriptor
|
||||||
|
dup2 Duplicates an open file descriptor
|
||||||
|
execl Executes a file
|
||||||
|
execle Executes a file
|
||||||
|
execlp Executes a file
|
||||||
|
execv Executes a file
|
||||||
|
execve Executes a file
|
||||||
|
execvp Executes a file
|
||||||
|
_exit Terminates a process
|
||||||
|
fcntl Manipulates an open file descriptor
|
||||||
|
fdopen Opens a stream on a file descriptor
|
||||||
|
fork Creates a process
|
||||||
|
fpathconf Gets configuration variable for an open file
|
||||||
|
fstat Gets file status
|
||||||
|
getcwd Gets current working directory
|
||||||
|
getegid Gets effective group ID
|
||||||
|
getenv Gets environment variable
|
||||||
|
geteuid Gets effective user ID
|
||||||
|
getgid Gets real group ID
|
||||||
|
getgrgid Reads groups database based on group ID
|
||||||
|
getgrnam Reads groups database based on group name
|
||||||
|
getgroups Gets supplementary group IDs
|
||||||
|
getlogin Gets user name
|
||||||
|
getpgrp Gets process group ID
|
||||||
|
getpid Gets process ID
|
||||||
|
getppid Gets parent process ID
|
||||||
|
getpwnam Reads user database based on user name
|
||||||
|
getpwuid Reads user database based on user ID
|
||||||
|
getuid Gets real user ID
|
||||||
|
isatty Determines if a file descriptor is associated with a terminal
|
||||||
|
kill Sends a kill signal to a process
|
||||||
|
link Creates a link to a file
|
||||||
|
longjmp Restores the calling environment
|
||||||
|
lseek Repositions read/write file offset
|
||||||
|
mkdir Makes a directory
|
||||||
|
mkfifo Makes a FIFO special file
|
||||||
|
open Opens a file
|
||||||
|
opendir Opens a directory
|
||||||
|
pathconf Gets configuration variables for a path
|
||||||
|
pause Suspends a process execution
|
||||||
|
pipe Creates an interprocess channel
|
||||||
|
read Reads from a file
|
||||||
|
readdir Reads a directory
|
||||||
|
rename Renames a file
|
||||||
|
rewinddir Resets the readdir() pointer
|
||||||
|
rmdir Removes a directory
|
||||||
|
setgid Sets group ID
|
||||||
|
setjmp Saves the calling environment for use by longjmp()
|
||||||
|
setlocale Sets or queries a program's locale
|
||||||
|
setpgid Sets a process group ID for job control
|
||||||
|
setuid Sets the user ID
|
||||||
|
sigaction Examines and changes signal action
|
||||||
|
sigaddset Adds a signal to a signal set
|
||||||
|
sigdelset Removes a signal to a signal set
|
||||||
|
sigemptyset Creates an empty signal set
|
||||||
|
sigfillset Creates a full set of signals
|
||||||
|
sigismember Tests a signal for a selected member
|
||||||
|
siglongjmp Goes to and restores signal mask
|
||||||
|
sigpending Examines pending signals
|
||||||
|
sigprocmask Examines and changes blocked signals
|
||||||
|
sigsetjmp Saves state for siglongjmp()
|
||||||
|
sigsuspend Waits for a signal
|
||||||
|
sleep Delays process execution
|
||||||
|
stat Gets information about a file
|
||||||
|
sysconf Gets system configuration information
|
||||||
|
tcdrain Waits for all output to be transmitted to the terminal
|
||||||
|
tcflow Suspends/restarts terminal output
|
||||||
|
tcflush Discards terminal data
|
||||||
|
tcgetattr Gets terminal attributes
|
||||||
|
tcgetpgrp Gets foreground process group ID
|
||||||
|
tcsendbreak Sends a break to a terminal
|
||||||
|
tcsetattr Sets terminal attributes
|
||||||
|
tcsetpgrp Sets foreground process group ID
|
||||||
|
time Determines the current calendar time
|
||||||
|
times Gets process times
|
||||||
|
ttyname Determines a terminal pathname
|
||||||
|
tzset Sets the timezone from environment variables
|
||||||
|
umask Sets the file creation mask
|
||||||
|
uname Gets system name
|
||||||
|
unlink Removes a directory entry
|
||||||
|
utime Sets file access and modification times
|
||||||
|
waitpid Waits for process termination
|
||||||
|
write Writes to a file
|
||||||
|
|
||||||
|
|
||||||
|
POSIX.1b function calls Function POSIX Description
|
||||||
|
aio_cancel Tries to cancel an asynchronous operation
|
||||||
|
aio_error Retrieves the error status for an asynchronous operation
|
||||||
|
aio_read Asynchronously reads from a file
|
||||||
|
aio_return Retrieves the return status for an asynchronous operation
|
||||||
|
aio_suspend Waits for an asynchronous operation to complete
|
||||||
|
aio_write Asynchronously writes to a file
|
||||||
|
clock_getres Gets resolution of a POSIX.1b clock
|
||||||
|
clock_gettime Gets the time according to a particular POSIX.1b clock
|
||||||
|
clock_settime Sets the time according to a particular POSIX.1b clock
|
||||||
|
fdatasync Synchronizes at least the data part of a file with the underlying media
|
||||||
|
fsync Synchronizes a file with the underlying media
|
||||||
|
kill, sigqueue Sends signals to a process
|
||||||
|
lio_listio Performs a list of I/O operations, synchronously or asynchronously
|
||||||
|
mlock Locks a range of memory
|
||||||
|
mlockall Locks the entire memory space down
|
||||||
|
mmap Maps a shared memory object (or possibly another file) into process's address space
|
||||||
|
mprotect Changes memory protection on a mapped area
|
||||||
|
mq_close Terminates access to a POSIX.1b message queue
|
||||||
|
mq_getattr Gets POSIX.1b message queue attributes
|
||||||
|
mq_notify Registers a request to be notified when a message arrives on an empty message queue
|
||||||
|
mq_open Creates/accesses a POSIX.1b message queue
|
||||||
|
mq_receive Receives a message from a POSIX.1b message queue
|
||||||
|
mq_send Sends a message on a POSIX.1b message queue
|
||||||
|
mq_setattr Sets a subset of POSIX.1b message queue attributes
|
||||||
|
msync Makes a mapping consistent with the underlying object
|
||||||
|
munlock Unlocks a range of memory
|
||||||
|
munlockall Unlocks the entire address space
|
||||||
|
munmap Undo mapping established by mmap
|
||||||
|
nanosleep Pauses execution for a number of nanoseconds
|
||||||
|
sched_get_priority_max Gets maximum priority value for a scheduler
|
||||||
|
sched_get_priority_min Gets minimum priority value for a scheduler
|
||||||
|
sched_getparam Retrieves scheduling parameters for a particular process
|
||||||
|
sched_getscheduler Retrieves scheduling algorithm for a particular purpose
|
||||||
|
sched_rr_get_interval Gets the SCHED_RR interval for the named process
|
||||||
|
sched_setparam Sets scheduling parameters for a process
|
||||||
|
sched_setscheduler Sets scheduling algorithm/parameters for a process
|
||||||
|
sched_yield Yields the processor
|
||||||
|
sem_close Terminates access to a POSIX.1b semaphore
|
||||||
|
sem_destroy De-initializes a POSIX.1b unnamed semaphore
|
||||||
|
sem_getvalue Gets the value of a POSIX.1b semaphore
|
||||||
|
sem_open Creates/accesses a POSIX.1b named semaphore
|
||||||
|
sem_post Posts (signal) a POSIX.1b named or unnamed semaphore
|
||||||
|
sem_unlink Destroys a POSIX.1b named semaphore
|
||||||
|
sem_wait, sem_trywait Waits on a POSIX.1b named or unnamed semaphore
|
||||||
|
shm_open Creates/accesses a POSIX.1b shared memory object
|
||||||
|
shm_unlink Destroys a POSIX.1b shared memory object
|
||||||
|
sigwaitinfosigtimedwait Synchronously awaits signal arrival; avoid calling handler
|
||||||
|
timer_create Creates a POSIX.1b timer based on a particular clock
|
||||||
|
timer_delete Deletes a POSIX.1b timer
|
||||||
|
timer_gettime Time remaining on a POSIX.1b timer before expiration
|
||||||
|
timer_settime Sets expiration time/interval for a POSIX.1b timer
|
||||||
|
wait, waitpid Retrieves status of a terminated process and clean up corpse
|
||||||
|
|
||||||
|
|
||||||
|
POSIX.1c function calls Function POSIX Description
|
||||||
|
pthread_atfork Declares procedures to be called before and after a fork
|
||||||
|
pthread_attr_destroy Destroys a thread attribute object
|
||||||
|
pthread_attr_getdetachstate Obtains the setting of the detached state of a thread
|
||||||
|
pthread_attr_getinheritsched Obtains the setting of the scheduling inheritance of a thread
|
||||||
|
pthread_attr_getschedparam Obtains the parameters associated with the scheduling policy attribute of a thread
|
||||||
|
pthread_attr_getschedpolicy Obtains the setting of the scheduling policy of a thread
|
||||||
|
pthread_attr_getscope Obtains the setting of the scheduling scope of a thread
|
||||||
|
pthread_attr_getstackaddr Obtains the stack address of a thread
|
||||||
|
pthread_attr_getstacksize Obtains the stack size of a thread
|
||||||
|
pthread_attr_init Initializes a thread attribute object
|
||||||
|
pthread_attr_setdetachstate Adjusts the detached state of a thread
|
||||||
|
pthread_attr_setinheritsched Adjusts the scheduling inheritance of a thread
|
||||||
|
pthread_attr_setschedparam Adjusts the parameters associated with the scheduling policy of a thread
|
||||||
|
pthread_attr_setschedpolicy Adjusts the scheduling policy of a thread
|
||||||
|
pthread_attr_setscope Adjusts the scheduling scope of a thread
|
||||||
|
pthread_attr_setstackaddr Adjusts the stack address of a thread
|
||||||
|
pthread_attr_setstacksize Adjusts the stack size of a thread
|
||||||
|
pthread_cancel Cancels the specific thread
|
||||||
|
pthread_cleanup_pop Removes the routine from the top of a thread's cleanup stack, and if execute is nonzero, runs it
|
||||||
|
pthread_cleanup_push Places a routine on the top of a thread's cleanup stack
|
||||||
|
pthread_condattr_destroy Destroys a condition variable attribute object
|
||||||
|
pthread_condattr_getpshared Obtains the process-shared setting of a condition variable attribute object
|
||||||
|
pthread_condattr_init Initializes a condition variable attribute object
|
||||||
|
pthread_condattr_setpshared Sets the process-shared attribute in a condition variable attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
|
||||||
|
pthread_cond_broadcast Unblocks all threads that are waiting on a condition variable
|
||||||
|
pthread_cond_destroy Destroys a condition variable
|
||||||
|
pthread_cond_init Initializes a condition variable with the attributes specified in the specified condition variable attribute object
|
||||||
|
pthread_cond_signal Unblocks at least one thread waiting on a condition variable
|
||||||
|
pthread_cond_timedwait Automatically unlocks the specified mutex, and places the calling thread into a wait state
|
||||||
|
pthread_cond_wait Automatically unlocks the specified mutex, and places the calling thread into a wait state
|
||||||
|
pthread_create Creates a thread with the attributes specified in attr
|
||||||
|
pthread_detach Marks a threads internal data structures for deletion
|
||||||
|
pthread_equal Compares one thread handle to another thread handle
|
||||||
|
pthread_exit Terminates the calling thread
|
||||||
|
pthread_getschedparam Obtains both scheduling policy and scheduling parameters of an existing thread
|
||||||
|
pthread_getspecific Obtains the thread specific data value associated with the specific key in the calling thread
|
||||||
|
pthread_join Causes the calling thread to wait for the specific thread’s termination
|
||||||
|
pthread_key_create Generates a unique thread-specific key that's visible to all threads in a process
|
||||||
|
pthread_key_delete Deletes a thread specific key
|
||||||
|
pthread_kill Delivers a signal to the specified thread
|
||||||
|
pthread_mutexattr_destroy Destroys a mutex attribute object
|
||||||
|
pthread_mutexattr_getprioceiling Obtains the priority ceiling of a mutex attribute object
|
||||||
|
pthread_mutexattr_getprotocol Obtains protocol of a mutex attribute object
|
||||||
|
pthread_mutexattr_getpshared Obtains a process-shared setting of a mutex attribute object
|
||||||
|
pthread_mutexattr_init Initializes a mutex attribute object
|
||||||
|
pthread_mutexattr_setprioceiling Sets the priority ceiling attribute of a mutex attribute object
|
||||||
|
pthread_mutexattr_setprotocol Sets the protocol attribute of a mutex attribute object
|
||||||
|
pthread_mutexattr_setpshared Sets the process-shared attribute of a mutex attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE
|
||||||
|
pthread_mutex_destroy Destroys a mutex
|
||||||
|
pthread_mutex_init Initializes a mutex with the attributes specified in the specified mutex attribute object
|
||||||
|
pthread_mutex_lock Locks an unlocked mutex
|
||||||
|
pthread_mutex_trylock Tries to lock a not tested
|
||||||
|
pthread_mutex_unlock Unlocks a mutex
|
||||||
|
pthread_once Ensures that init_routine will run just once regardless of how many threads in the process call it
|
||||||
|
pthread_self Obtains a thread handle of a calling thread
|
||||||
|
pthread_setcancelstate Sets a thread's cancelability state
|
||||||
|
pthread_setcanceltype Sets a thread's cancelability type
|
||||||
|
pthread_setschedparam Adjusts the scheduling policy and scheduling parameters of an existing thread
|
||||||
|
pthread_setspecific Sets the thread-specific data value associated with the specific key in the calling thread
|
||||||
|
pthread_sigmask Examines or changes the calling thread's signal mask
|
||||||
|
pthread_testcancel Requests that any pending cancellation request be delivered to the calling thread
|
||||||
|
|
||||||
|
|
||||||
11
doc/readme.txt
Executable file
11
doc/readme.txt
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
============================
|
||||||
|
Nimrod's documenation system
|
||||||
|
============================
|
||||||
|
|
||||||
|
This folder contains Nimrod's documentation. The documentation
|
||||||
|
is written in a format called *reStructuredText*, a markup language that reads
|
||||||
|
like ASCII and can be converted to HTML, Tex and other formats automatically!
|
||||||
|
|
||||||
|
Unfortunately reStructuredText does not allow to colorize source code in the
|
||||||
|
HTML page. Therefore a postprocessor runs over the generated HTML code, looking
|
||||||
|
for Nimrod code fragments and colorizing them.
|
||||||
296
doc/regexprs.txt
Executable file
296
doc/regexprs.txt
Executable file
|
|
@ -0,0 +1,296 @@
|
||||||
|
Licence of the PCRE library
|
||||||
|
===========================
|
||||||
|
|
||||||
|
PCRE is a library of functions to support regular expressions whose
|
||||||
|
syntax and semantics are as close as possible to those of the Perl 5
|
||||||
|
language.
|
||||||
|
|
||||||
|
| Written by Philip Hazel
|
||||||
|
| Copyright (c) 1997-2005 University of Cambridge
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the University of Cambridge nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
Regular expression syntax and semantics
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
As the regular expressions supported by this module are enormous,
|
||||||
|
the reader is referred to http://perldoc.perl.org/perlre.html for the
|
||||||
|
full documentation of Perl's regular expressions.
|
||||||
|
|
||||||
|
Because the backslash ``\`` is a meta character both in the Nimrod
|
||||||
|
programming language and in regular expressions, it is strongly
|
||||||
|
recommended that one uses the *raw* strings of Nimrod, so that
|
||||||
|
backslashes are interpreted by the regular expression engine::
|
||||||
|
|
||||||
|
r"\S" # matches any character that is not whitespace
|
||||||
|
|
||||||
|
A regular expression is a pattern that is matched against a subject string
|
||||||
|
from left to right. Most characters stand for themselves in a pattern, and
|
||||||
|
match the corresponding characters in the subject. As a trivial example,
|
||||||
|
the pattern::
|
||||||
|
|
||||||
|
The quick brown fox
|
||||||
|
|
||||||
|
matches a portion of a subject string that is identical to itself.
|
||||||
|
The power of regular expressions comes from the ability to include
|
||||||
|
alternatives and repetitions in the pattern. These are encoded in
|
||||||
|
the pattern by the use of metacharacters, which do not stand for
|
||||||
|
themselves but instead are interpreted in some special way.
|
||||||
|
|
||||||
|
There are two different sets of metacharacters: those that are recognized
|
||||||
|
anywhere in the pattern except within square brackets, and those that are
|
||||||
|
recognized in square brackets. Outside square brackets, the metacharacters
|
||||||
|
are as follows:
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
meta character meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\`` general escape character with several uses
|
||||||
|
``^`` assert start of string (or line, in multiline mode)
|
||||||
|
``$`` assert end of string (or line, in multiline mode)
|
||||||
|
``.`` match any character except newline (by default)
|
||||||
|
``[`` start character class definition
|
||||||
|
``|`` start of alternative branch
|
||||||
|
``(`` start subpattern
|
||||||
|
``)`` end subpattern
|
||||||
|
``?`` extends the meaning of ``(``
|
||||||
|
also 0 or 1 quantifier
|
||||||
|
also quantifier minimizer
|
||||||
|
``*`` 0 or more quantifier
|
||||||
|
``+`` 1 or more quantifier
|
||||||
|
also "possessive quantifier"
|
||||||
|
``{`` start min/max quantifier
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
Part of a pattern that is in square brackets is called a "character class".
|
||||||
|
In a character class the only metacharacters are:
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
meta character meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\`` general escape character
|
||||||
|
``^`` negate the class, but only if the first character
|
||||||
|
``-`` indicates character range
|
||||||
|
``[`` POSIX character class (only if followed by POSIX syntax)
|
||||||
|
``]`` terminates the character class
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
The following sections describe the use of each of the metacharacters.
|
||||||
|
|
||||||
|
|
||||||
|
Backslash
|
||||||
|
---------
|
||||||
|
The `backslash`:idx: character has several uses. Firstly, if it is followed
|
||||||
|
by a non-alphanumeric character, it takes away any special meaning that
|
||||||
|
character may have. This use of backslash as an escape character applies
|
||||||
|
both inside and outside character classes.
|
||||||
|
|
||||||
|
For example, if you want to match a ``*`` character, you write ``\*`` in
|
||||||
|
the pattern. This escaping action applies whether or not the following
|
||||||
|
character would otherwise be interpreted as a metacharacter, so it is always
|
||||||
|
safe to precede a non-alphanumeric with backslash to specify that it stands
|
||||||
|
for itself. In particular, if you want to match a backslash, you write ``\\``.
|
||||||
|
|
||||||
|
|
||||||
|
Non-printing characters
|
||||||
|
-----------------------
|
||||||
|
A second use of backslash provides a way of encoding non-printing characters
|
||||||
|
in patterns in a visible manner. There is no restriction on the appearance of
|
||||||
|
non-printing characters, apart from the binary zero that terminates a pattern,
|
||||||
|
but when a pattern is being prepared by text editing, it is usually easier to
|
||||||
|
use one of the following escape sequences than the binary character it
|
||||||
|
represents::
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
character meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\a`` alarm, that is, the BEL character (hex 07)
|
||||||
|
``\e`` escape (hex 1B)
|
||||||
|
``\f`` formfeed (hex 0C)
|
||||||
|
``\n`` newline (hex 0A)
|
||||||
|
``\r`` carriage return (hex 0D)
|
||||||
|
``\t`` tab (hex 09)
|
||||||
|
``\ddd`` character with octal code ddd, or backreference
|
||||||
|
``\xhh`` character with hex code hh
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
After ``\x``, from zero to two hexadecimal digits are read (letters can be in
|
||||||
|
upper or lower case). In UTF-8 mode, any number of hexadecimal digits may
|
||||||
|
appear between ``\x{`` and ``}``, but the value of the character code must be
|
||||||
|
less than 2**31 (that is, the maximum hexadecimal value is 7FFFFFFF). If
|
||||||
|
characters other than hexadecimal digits appear between ``\x{`` and ``}``, or
|
||||||
|
if there is no terminating ``}``, this form of escape is not recognized.
|
||||||
|
Instead, the initial ``\x`` will be interpreted as a basic hexadecimal escape,
|
||||||
|
with no following digits, giving a character whose value is zero.
|
||||||
|
|
||||||
|
After ``\0`` up to two further octal digits are read. In both cases, if there
|
||||||
|
are fewer than two digits, just those that are present are used. Thus the
|
||||||
|
sequence ``\0\x\07`` specifies two binary zeros followed by a BEL character
|
||||||
|
(code value 7). Make sure you supply two digits after the initial zero if
|
||||||
|
the pattern character that follows is itself an octal digit.
|
||||||
|
|
||||||
|
The handling of a backslash followed by a digit other than 0 is complicated.
|
||||||
|
Outside a character class, PCRE reads it and any following digits as a
|
||||||
|
decimal number. If the number is less than 10, or if there have been at least
|
||||||
|
that many previous capturing left parentheses in the expression, the entire
|
||||||
|
sequence is taken as a back reference. A description of how this works is
|
||||||
|
given later, following the discussion of parenthesized subpatterns.
|
||||||
|
|
||||||
|
Inside a character class, or if the decimal number is greater than 9 and
|
||||||
|
there have not been that many capturing subpatterns, PCRE re-reads up to
|
||||||
|
three octal digits following the backslash, and generates a single byte
|
||||||
|
from the least significant 8 bits of the value. Any subsequent digits stand
|
||||||
|
for themselves. For example:
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
example meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\040`` is another way of writing a space
|
||||||
|
``\40`` is the same, provided there are fewer than 40 previous
|
||||||
|
capturing subpatterns
|
||||||
|
``\7`` is always a back reference
|
||||||
|
``\11`` might be a back reference, or another way of writing a tab
|
||||||
|
``\011`` is always a tab
|
||||||
|
``\0113`` is a tab followed by the character "3"
|
||||||
|
``\113`` might be a back reference, otherwise the character with
|
||||||
|
octal code 113
|
||||||
|
``\377`` might be a back reference, otherwise the byte consisting
|
||||||
|
entirely of 1 bits
|
||||||
|
``\81`` is either a back reference, or a binary zero followed by
|
||||||
|
the two characters "8" and "1"
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
Note that octal values of 100 or greater must not be introduced by a leading
|
||||||
|
zero, because no more than three octal digits are ever read.
|
||||||
|
|
||||||
|
All the sequences that define a single byte value or a single UTF-8 character
|
||||||
|
(in UTF-8 mode) can be used both inside and outside character classes. In
|
||||||
|
addition, inside a character class, the sequence ``\b`` is interpreted as the
|
||||||
|
backspace character (hex 08), and the sequence ``\X`` is interpreted as the
|
||||||
|
character "X". Outside a character class, these sequences have different
|
||||||
|
meanings (see below).
|
||||||
|
|
||||||
|
Generic character types
|
||||||
|
-----------------------
|
||||||
|
The third use of backslash is for specifying `generic character types`:idx:.
|
||||||
|
The following are always recognized:
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
character type meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\d`` any decimal digit
|
||||||
|
``\D`` any character that is not a decimal digit
|
||||||
|
``\s`` any whitespace character
|
||||||
|
``\S`` any character that is not a whitespace character
|
||||||
|
``\w`` any "word" character
|
||||||
|
``\W`` any "non-word" character
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
Each pair of escape sequences partitions the complete set of characters into
|
||||||
|
two disjoint sets. Any given character matches one, and only one, of each pair.
|
||||||
|
|
||||||
|
These character type sequences can appear both inside and outside character
|
||||||
|
classes. They each match one character of the appropriate type. If the
|
||||||
|
current matching point is at the end of the subject string, all of them fail,
|
||||||
|
since there is no character to match.
|
||||||
|
|
||||||
|
For compatibility with Perl, ``\s`` does not match the VT character (code 11).
|
||||||
|
This makes it different from the the POSIX "space" class. The ``\s`` characters
|
||||||
|
are HT (9), LF (10), FF (12), CR (13), and space (32).
|
||||||
|
|
||||||
|
A "word" character is an underscore or any character less than 256 that is
|
||||||
|
a letter or digit. The definition of letters and digits is controlled by
|
||||||
|
PCRE's low-valued character tables, and may vary if locale-specific matching
|
||||||
|
is taking place (see "Locale support" in the pcreapi page). For example,
|
||||||
|
in the "fr_FR" (French) locale, some character codes greater than 128 are
|
||||||
|
used for accented letters, and these are matched by ``\w``.
|
||||||
|
|
||||||
|
In UTF-8 mode, characters with values greater than 128 never match ``\d``,
|
||||||
|
``\s``, or ``\w``, and always match ``\D``, ``\S``, and ``\W``. This is true
|
||||||
|
even when Unicode character property support is available.
|
||||||
|
|
||||||
|
Simple assertions
|
||||||
|
-----------------
|
||||||
|
The fourth use of backslash is for certain `simple assertions`:idx:. An
|
||||||
|
assertion specifies a condition that has to be met at a particular point in
|
||||||
|
a match, without consuming any characters from the subject string. The use of
|
||||||
|
subpatterns for more complicated assertions is described below. The
|
||||||
|
backslashed assertions are::
|
||||||
|
|
||||||
|
============== ============================================================
|
||||||
|
assertion meaning
|
||||||
|
============== ============================================================
|
||||||
|
``\b`` matches at a word boundary
|
||||||
|
``\B`` matches when not at a word boundary
|
||||||
|
``\A`` matches at start of subject
|
||||||
|
``\Z`` matches at end of subject or before newline at end
|
||||||
|
``\z`` matches at end of subject
|
||||||
|
``\G`` matches at first matching position in subject
|
||||||
|
============== ============================================================
|
||||||
|
|
||||||
|
These assertions may not appear in character classes (but note that ``\b``
|
||||||
|
has a different meaning, namely the backspace character, inside a character
|
||||||
|
class).
|
||||||
|
|
||||||
|
A word boundary is a position in the subject string where the current
|
||||||
|
character and the previous character do not both match ``\w`` or ``\W`` (i.e.
|
||||||
|
one matches ``\w`` and the other matches ``\W``), or the start or end of the
|
||||||
|
string if the first or last character matches ``\w``, respectively.
|
||||||
|
|
||||||
|
The ``\A``, ``\Z``, and ``\z`` assertions differ from the traditional
|
||||||
|
circumflex and dollar in that they only ever match at the very start and
|
||||||
|
end of the subject string, whatever options are set.
|
||||||
|
The difference between ``\Z`` and ``\z`` is that ``\Z`` matches before
|
||||||
|
a newline that is the last character of the string as well as at the end
|
||||||
|
of the string, whereas ``\z`` matches only at the end.
|
||||||
|
|
||||||
|
..
|
||||||
|
Regular expressions in Nimrod itself!
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
'a' -- matches the character a
|
||||||
|
'a'-'z' -- range operator '-'
|
||||||
|
'A' | 'B' -- alternative operator |
|
||||||
|
* 'a' -- prefix * is needed
|
||||||
|
+ 'a' -- prefix + is needed
|
||||||
|
? 'a' -- prefix ? is needed
|
||||||
|
letter -- character classes with real names!
|
||||||
|
letters
|
||||||
|
white
|
||||||
|
whites
|
||||||
|
any -- any character
|
||||||
|
() -- are Nimrod syntax
|
||||||
|
! 'a'-'z'
|
||||||
|
|
||||||
|
-- concatentation via proc call:
|
||||||
|
|
||||||
|
re('A' 'Z' word * )
|
||||||
111
doc/rst.txt
Executable file
111
doc/rst.txt
Executable file
|
|
@ -0,0 +1,111 @@
|
||||||
|
===========================================================================
|
||||||
|
Nimrod's implementation of |rst|
|
||||||
|
===========================================================================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
:Version: |nimrodversion|
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document describes the subset of `Docutils`_' `reStructuredText`_ as it
|
||||||
|
has been implemented in the Nimrod compiler for generating documentation.
|
||||||
|
Elements of |rst| that are not listed here have not been implemented.
|
||||||
|
Unfortunately, the specification of |rst| is quite vague, so Nimrod is not as
|
||||||
|
compatible to the original implementation as one would like.
|
||||||
|
|
||||||
|
Even though Nimrod's |rst| parser does not parse all constructs, it is pretty
|
||||||
|
usable. The missing features can easily be circumvented. An indication of this
|
||||||
|
fact is that Nimrod's
|
||||||
|
*whole* documentation itself (including this document) is
|
||||||
|
processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than
|
||||||
|
Docutils' parser.)
|
||||||
|
|
||||||
|
|
||||||
|
Inline elements
|
||||||
|
===============
|
||||||
|
|
||||||
|
Ordinary text may contain *inline elements*.
|
||||||
|
|
||||||
|
|
||||||
|
Bullet lists
|
||||||
|
============
|
||||||
|
|
||||||
|
*Bullet lists* look like this::
|
||||||
|
|
||||||
|
* Item 1
|
||||||
|
* Item 2 that
|
||||||
|
spans over multiple lines
|
||||||
|
* Item 3
|
||||||
|
* Item 4
|
||||||
|
- bullet lists may nest
|
||||||
|
- item 3b
|
||||||
|
- valid bullet characters are ``+``, ``*`` and ``-``
|
||||||
|
|
||||||
|
This results in:
|
||||||
|
* Item 1
|
||||||
|
* Item 2 that
|
||||||
|
spans over multiple lines
|
||||||
|
* Item 3
|
||||||
|
* Item 4
|
||||||
|
- bullet lists may nest
|
||||||
|
- item 3b
|
||||||
|
- valid bullet characters are ``+``, ``*`` and ``-``
|
||||||
|
|
||||||
|
|
||||||
|
Enumerated lists
|
||||||
|
================
|
||||||
|
|
||||||
|
*Enumerated lists*
|
||||||
|
|
||||||
|
|
||||||
|
Defintion lists
|
||||||
|
===============
|
||||||
|
|
||||||
|
Save this code to the file "greeting.nim". Now compile and run it:
|
||||||
|
|
||||||
|
``nimrod run greeting.nim``
|
||||||
|
|
||||||
|
As you see, with the ``run`` command Nimrod executes the file automatically
|
||||||
|
after compilation. You can even give your program command line arguments by
|
||||||
|
appending them after the filename that is to be compiled and run:
|
||||||
|
|
||||||
|
``nimrod run greeting.nim arg1 arg2``
|
||||||
|
|
||||||
|
|
||||||
|
Tables
|
||||||
|
======
|
||||||
|
|
||||||
|
Nimrod only implements simple tables of the form::
|
||||||
|
|
||||||
|
================== =============== ===================
|
||||||
|
header 1 header 2 header n
|
||||||
|
================== =============== ===================
|
||||||
|
Cell 1 Cell 2 Cell 3
|
||||||
|
Cell 4 Cell 5; any Cell 6
|
||||||
|
cell that is
|
||||||
|
not in column 1
|
||||||
|
may span over
|
||||||
|
multiple lines
|
||||||
|
Cell 7 Cell 8 Cell 9
|
||||||
|
================== =============== ===================
|
||||||
|
|
||||||
|
This results in:
|
||||||
|
================== =============== ===================
|
||||||
|
header 1 header 2 header n
|
||||||
|
================== =============== ===================
|
||||||
|
Cell 1 Cell 2 Cell 3
|
||||||
|
Cell 4 Cell 5; any Cell 6
|
||||||
|
cell that is
|
||||||
|
not in column 1
|
||||||
|
may span over
|
||||||
|
multiple lines
|
||||||
|
Cell 7 Cell 8 Cell 9
|
||||||
|
================== =============== ===================
|
||||||
|
|
||||||
|
|
||||||
|
.. |rst| replace:: reStructuredText
|
||||||
|
.. _reStructuredText: http://docutils.sourceforge.net/rst.html#reference-documentation
|
||||||
|
.. _docutils: http://docutils.sourceforge.net/
|
||||||
1297
doc/spec.txt
Executable file
1297
doc/spec.txt
Executable file
File diff suppressed because it is too large
Load diff
1436
doc/theindex.txt
Executable file
1436
doc/theindex.txt
Executable file
File diff suppressed because it is too large
Load diff
215
doc/tutorial.txt
Executable file
215
doc/tutorial.txt
Executable file
|
|
@ -0,0 +1,215 @@
|
||||||
|
===========================================
|
||||||
|
Tutorial of the Nimrod Programming Language
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
:Author: Andreas Rumpf
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Why yet another programming language?
|
||||||
|
|
||||||
|
Look at the trends behind all the new programming languages:
|
||||||
|
|
||||||
|
* They try to be dynamic: Dynamic typing, dynamic method binding, etc.
|
||||||
|
In my opinion the most things the dynamic features buy could be achieved
|
||||||
|
with static means in a more efficient and *understandable* way.
|
||||||
|
|
||||||
|
* They depend on big runtime environments which you need to
|
||||||
|
ship with your program as each new version of these may break compability
|
||||||
|
in subtle ways or you use recently added features - thus forcing your
|
||||||
|
users to update their runtime environment. Compiled programs where the
|
||||||
|
executable contains all needed code are simply the better solution.
|
||||||
|
|
||||||
|
* They are unsuitable for systems programming: Do you really want to
|
||||||
|
write an operating system, a device driver or an interpreter in a language
|
||||||
|
that is just-in-time compiled (or interpreted)?
|
||||||
|
|
||||||
|
|
||||||
|
So what lacks are *good* systems programming languages. Nimrod is such a
|
||||||
|
language. It offers the following features:
|
||||||
|
|
||||||
|
* It is readable: It reads from left to right (unlike the C-syntax
|
||||||
|
languages).
|
||||||
|
* It is strongly and statically typed: This enables the compiler to find
|
||||||
|
more errors. Static typing also makes programs more *readable*.
|
||||||
|
* It is compiled. (Currently this is done via compilation to C.)
|
||||||
|
* It is garbage collected. Big systems need garbage collection. Manuell
|
||||||
|
memory management is also supported through *untraced pointers*.
|
||||||
|
* It scales because high level features are also available: It has built-in
|
||||||
|
bit sets, strings, enumerations, objects, arrays and dynamically resizeable
|
||||||
|
arrays (called *sequences*).
|
||||||
|
* It has high performance: The current implementation compiles to C
|
||||||
|
and uses a Deutsch-Bobrow garbage collector together with Christoper's
|
||||||
|
partial mark-sweep garbage collector leading to excellent execution
|
||||||
|
speed and a small memory footprint.
|
||||||
|
* It has real modules with proper interfaces and supports separate
|
||||||
|
compilation.
|
||||||
|
* It is portable: It compiles to C and platform specific features have
|
||||||
|
been separated and documented. So even if your platform is not supported
|
||||||
|
porting should be easy.
|
||||||
|
* It is flexible: Although primilarily a procedural language, generic,
|
||||||
|
functional and object-oriented programming is also supported.
|
||||||
|
* It is easy to learn, easy to use and leads to elegant programs.
|
||||||
|
* You can link an embedded debugger to your program (ENDB). ENDB is
|
||||||
|
very easy to use - there is no need to clutter your code with
|
||||||
|
``echo`` statements for proper debugging.
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
This document is a tutorial for the programming language *Nimrod*. It should
|
||||||
|
be a readable quick tour through the language instead of a dry specification
|
||||||
|
(which can be found `here <manual.html>`_). This tutorial assumes that
|
||||||
|
the reader already knows some other programming language such as Pascal. Thus
|
||||||
|
it is detailed in cases where Nimrod differs from other programming languages
|
||||||
|
and kept short where Nimrod is more or less the same.
|
||||||
|
|
||||||
|
|
||||||
|
A quick tour through the language
|
||||||
|
=================================
|
||||||
|
|
||||||
|
The first program
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
We start the tour with a modified "hallo world" program:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
# This is a comment
|
||||||
|
# Standard IO-routines are always accessible
|
||||||
|
write(stdout, "What's your name? ")
|
||||||
|
var name: string = readLine(stdin)
|
||||||
|
write(stdout, "Hi, " & name & "!\n")
|
||||||
|
|
||||||
|
|
||||||
|
Save this code to the file "greeting.nim". Now compile and run it::
|
||||||
|
|
||||||
|
nimrod run greeting.nim
|
||||||
|
|
||||||
|
As you see, with the ``run`` command Nimrod executes the file automatically
|
||||||
|
after compilation. You can even give your program command line arguments by
|
||||||
|
appending them after the filename that is to be compiled and run::
|
||||||
|
|
||||||
|
nimrod run greeting.nim arg1 arg2
|
||||||
|
|
||||||
|
Though it should be pretty obvious what the program does, I will explain the
|
||||||
|
syntax: Statements which are not indented are executed when the program
|
||||||
|
starts. Indentation is Nimrod's way of grouping statements. String literals
|
||||||
|
are enclosed in double quotes. The ``var`` statement declares a new variable
|
||||||
|
named ``name`` of type ``string`` with the value that is returned by the
|
||||||
|
``readline`` procedure. Since the compiler knows that ``readline`` returns
|
||||||
|
a string, you can leave out the type in the declaration. So this will work too:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var name = readline(stdin)
|
||||||
|
|
||||||
|
Note that this is the only form of type inference that exists in Nimrod:
|
||||||
|
This is because it yields a good compromise between brevity and readability.
|
||||||
|
|
||||||
|
The ``&`` operator concates strings together. ``\n`` stands for the
|
||||||
|
new line character(s). On several operating systems ``\n`` is represented by
|
||||||
|
*two* characters: Linefeed and Carriage Return. That is why
|
||||||
|
*character literals* cannot contain ``\n``. But since Nimrod handles strings
|
||||||
|
so well, this is a nonissue.
|
||||||
|
|
||||||
|
The "hallo world" program contains several identifiers that are already
|
||||||
|
known to the compiler: ``write``, ``stdout``, ``readLine``, etc. These
|
||||||
|
built-in items are declared in the system_ module which is implicitly
|
||||||
|
imported by any other module.
|
||||||
|
|
||||||
|
|
||||||
|
Lexical elements
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Let us look into Nimrod's lexical elements in more detail: Like other
|
||||||
|
programming languages Nimrod consists of identifiers, keywords, comments,
|
||||||
|
operators, and other punctation marks. Case is *insignificant* in Nimrod and
|
||||||
|
even underscores are ignored: ``This_is_an_identifier`` and this is the same
|
||||||
|
identifier ``ThisIsAnIdentifier``. This feature enables one to use other
|
||||||
|
peoples code without bothering about a naming convention that one does not
|
||||||
|
like.
|
||||||
|
|
||||||
|
String literals are enclosed in double quotes, character literals in single
|
||||||
|
quotes. There exist also *raw* string and character literals:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
r"C:\program files\nim"
|
||||||
|
|
||||||
|
In raw literals the backslash is not an escape character, so they fit
|
||||||
|
the principle *what you see is what you get*. *Long string literals*
|
||||||
|
are also available (``""" ... """``); they can span over multiple lines
|
||||||
|
and the ``\`` is not an escape character either. They are very useful
|
||||||
|
for embedding SQL code templates for example.
|
||||||
|
|
||||||
|
Comments start with ``#`` and run till the end of the line. (Well this is not
|
||||||
|
quite true, but you should read the manual for a proper explanation.)
|
||||||
|
|
||||||
|
... XXX number literals
|
||||||
|
|
||||||
|
|
||||||
|
The usual statements - if, while, for, case
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
In Nimrod indentation is used to group statements.
|
||||||
|
An example showing the most common statement types:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
var name = readLine(stdin)
|
||||||
|
|
||||||
|
if name == "Andreas":
|
||||||
|
echo("What a nice name!")
|
||||||
|
elif name == "":
|
||||||
|
echo("Don't you have a name?")
|
||||||
|
else:
|
||||||
|
echo("Boring name...")
|
||||||
|
|
||||||
|
for i in 0..length(name)-1:
|
||||||
|
if name[i] == 'm':
|
||||||
|
echo("hey, there is an *m* in your name!")
|
||||||
|
|
||||||
|
echo("Please give your password: \n")
|
||||||
|
var pw = readLine(stdin)
|
||||||
|
|
||||||
|
while pw != "12345":
|
||||||
|
echo("Wrong password! Next try: \n")
|
||||||
|
pw = readLine(stdin)
|
||||||
|
|
||||||
|
echo("""Login complete!
|
||||||
|
What do you want to do?
|
||||||
|
delete-everything
|
||||||
|
restart-computer
|
||||||
|
go-for-a-walk
|
||||||
|
""")
|
||||||
|
|
||||||
|
case readline(stdin)
|
||||||
|
of "delete-everything", "restart-computer":
|
||||||
|
echo("permission denied")
|
||||||
|
of "go-for-a-walk": echo("please yourself")
|
||||||
|
else: echo("unknown command")
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Types
|
||||||
|
-----
|
||||||
|
|
||||||
|
Nimrod has a rich type system. This tutorial only gives a few examples. Read
|
||||||
|
the `manual <manual.html>`_ for further information:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
type
|
||||||
|
TMyRecord = record
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
|
||||||
|
Procedures
|
||||||
|
----------
|
||||||
|
|
||||||
|
Procedures are subroutines. They are declared in this way:
|
||||||
|
|
||||||
|
.. code-block:: Nimrod
|
||||||
|
proc findSubStr(sub: string,
|
||||||
|
|
||||||
|
|
||||||
|
.. _strutils: strutils.html
|
||||||
|
.. _system: system.html
|
||||||
24
dos2unix.py
Executable file
24
dos2unix.py
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
"Replace CRLF with LF in argument files. Print names of changed files."
|
||||||
|
|
||||||
|
import sys, os, glob
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for arg in sys.argv[1:]:
|
||||||
|
for filename in glob.glob(arg):
|
||||||
|
if os.path.isdir(filename):
|
||||||
|
print filename, "Directory!"
|
||||||
|
continue
|
||||||
|
data = open(filename, "rb").read()
|
||||||
|
if '\0' in data:
|
||||||
|
print filename, "Binary!"
|
||||||
|
continue
|
||||||
|
newdata = data.replace("\r\n", "\n")
|
||||||
|
if newdata != data:
|
||||||
|
print filename
|
||||||
|
f = open(filename, "wb")
|
||||||
|
f.write(newdata)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
302
gcccpuopt.sh
Executable file
302
gcccpuopt.sh
Executable file
|
|
@ -0,0 +1,302 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Print the gcc cpu specific options appropriate for the current CPU
|
||||||
|
|
||||||
|
# Author:
|
||||||
|
# http://www.pixelbeat.org/
|
||||||
|
# Notes:
|
||||||
|
# This script currently supports Linux,FreeBSD,Cygwin
|
||||||
|
# This script is x86 (32 bit) specific
|
||||||
|
# It should work on any gcc >= 2.95 at least
|
||||||
|
# It only returns CPU specific options. You probably also want -03 etc.
|
||||||
|
# Changes:
|
||||||
|
# V0.1, 12 Mar 2003, Initial release
|
||||||
|
# V0.2, 01 Jun 2005, Added support for 3.2>=gcc<=4.0
|
||||||
|
# V0.3, 03 Jun 2005, Added support for pentium-m
|
||||||
|
# V0.4, 03 Jun 2005, Fix silly bugs
|
||||||
|
# V0.5, 07 Jun 2005, Clarify/Simplify confusing floating point expr usage
|
||||||
|
# Print warning when CPU only supported on a newer gcc
|
||||||
|
# V0.6, 15 Dec 2006, Added support for Intel Core and Core 2 processors
|
||||||
|
# Added support for 4.1>=gcc<=4.3
|
||||||
|
# Added support for gcc -msse3 option
|
||||||
|
# Added support for new gcc -march=native option
|
||||||
|
# V0.7, 18 Dec 2006, Changes from Conor McDermottroe
|
||||||
|
# Added support for FreeBSD
|
||||||
|
# Remove bash specific constructs
|
||||||
|
# Better error handling
|
||||||
|
# V0.8, 19 Dec 2006, Give warnings and 32 bit -march on 64 bit platforms.
|
||||||
|
# Previously it just gave an invalid blank -march.
|
||||||
|
# Reported and tested by Ewan Oughton.
|
||||||
|
# V0.9, 30 Apr 2007, Give error if compiler not present.
|
||||||
|
# Warn about rather than default to -march=native option.
|
||||||
|
# V0.92, 08 Nov 2007, Change from Krzysztof Jankowski to support Cygwin.
|
||||||
|
# Added support for AMD family 10 processors.
|
||||||
|
# Add support for gcc -msse4 & -msse5 options.
|
||||||
|
# Use "prescott" rather than "pentium4" for all
|
||||||
|
# models >= 3 in intel family 15, not just model 3.
|
||||||
|
# V0.93, 13 Nov 2007, Oops, actually not all intel family 15, model >= 3
|
||||||
|
# are prescotts. Use the sse3 flag to distinguish.
|
||||||
|
# V0.94, 31 Dec 2007, Oops, actually all intel family 15, model >= 3
|
||||||
|
# are prescotts. This was indicated by Adam Drzewiecki.
|
||||||
|
# I was confused by a bug in older linux kernels where pni
|
||||||
|
# was not reported for my intel "F41" processor at least.
|
||||||
|
# V0.95, 18 Jan 2008, Changes from Conor McDermottroe
|
||||||
|
# Support for Mac OS X
|
||||||
|
# Support for FreeBSD base system
|
||||||
|
|
||||||
|
if [ "$1" = "--version" ]; then
|
||||||
|
echo "0.95" && exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This table shows when -march options were introduced into _official_ gcc releases.
|
||||||
|
# Note there are vendor deviations that complicate this.
|
||||||
|
# For e.g. redhat introduced the prescott option in 3.3-13.
|
||||||
|
# gcc-2.95 = i386, i486, i586,pentium, i686,pentiumpro, k6
|
||||||
|
# gcc-3.0 += athlon
|
||||||
|
# gcc-3.1 += pentium-mmx, pentium2, pentium3, pentium4, k6-2, k6-3, athlon-{tbird, 4,xp,mp}
|
||||||
|
# gcc-3.3 += winchip-c6, winchip2, c3
|
||||||
|
# gcc-3.4.0 += k8,opteron,athlon64,athlon-fx, c3-2
|
||||||
|
# gcc-3.4.1 += pentium-m, pentium3m, pentium4m, prescott, nocona
|
||||||
|
# gcc-4.3 += core2, amdfam10
|
||||||
|
|
||||||
|
[ -z "$CC" ] && CC=gcc
|
||||||
|
|
||||||
|
try_gcc_options() {
|
||||||
|
$CC $* -S -o /dev/null -xc /dev/null >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! try_gcc_options; then
|
||||||
|
echo "Error: Couldn't execute your compiler ($CC)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if try_gcc_options -march=native; then
|
||||||
|
echo "Warning: Your compiler supports the -march=native option which you may prefer" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! try_gcc_options -march=i386; then
|
||||||
|
if ! try_gcc_options -m32 -march=i386; then
|
||||||
|
echo "Error: This script only supports 32 bit x86 architectures" >&2
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Warning: The optimum *32 bit* architecture is reported" >&2
|
||||||
|
m32="-m32 "
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
try_line() {
|
||||||
|
skip=0
|
||||||
|
for arch in $1; do
|
||||||
|
if try_gcc_options $m32 -march=$arch; then
|
||||||
|
echo $arch
|
||||||
|
return
|
||||||
|
elif [ "$skip" = "0" ] && [ "$arch" != "native" ]; then
|
||||||
|
skip=1
|
||||||
|
echo "Warning: Newer versions of GCC better support your CPU with -march=$arch" >&2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_data_linux() {
|
||||||
|
IFS=":"
|
||||||
|
while read name value; do
|
||||||
|
unset IFS
|
||||||
|
name=`echo $name`
|
||||||
|
value=`echo $value`
|
||||||
|
IFS=":"
|
||||||
|
if [ "$name" = "vendor_id" ]; then
|
||||||
|
vendor_id="$value"
|
||||||
|
elif [ "$name" = "cpu family" ]; then
|
||||||
|
cpu_family="$value"
|
||||||
|
elif [ "$name" = "model" ]; then
|
||||||
|
cpu_model="$value"
|
||||||
|
elif [ "$name" = "flags" ]; then
|
||||||
|
flags="$value"
|
||||||
|
break #flags last so break early
|
||||||
|
fi
|
||||||
|
done < /proc/cpuinfo
|
||||||
|
unset IFS
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_data_freebsd() {
|
||||||
|
local _line _cpu_id
|
||||||
|
|
||||||
|
if [ ! -r /var/run/dmesg.boot ]; then
|
||||||
|
echo "/var/run/dmesg.boot does not exist!"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS="
|
||||||
|
"
|
||||||
|
for _line in `grep -A2 '^CPU: ' /var/run/dmesg.boot`; do
|
||||||
|
if [ -n "`echo $_line | grep '^ Origin = '`" ]; then
|
||||||
|
vendor_id="`echo $_line | sed -e 's/^ Origin = .//' -e 's/[^A-Za-z0-9].*$//'`"
|
||||||
|
_cpu_id="`echo $_line | sed -e 's/^.*Id = //' -e 's/ .*$//' -e 'y/abcdef/ABCDEF/'`"
|
||||||
|
cpu_family=$((($_cpu_id & 0xF0F) >> 8))
|
||||||
|
cpu_model=$((($_cpu_id & 0xF0) >> 4))
|
||||||
|
fi
|
||||||
|
if [ -n "`echo $_line | grep '^ Features='`" ]; then
|
||||||
|
flags="`echo $_line | sed -e 's/^.*<//' -e 's/>.*//' -e 's/,/ /g' | tr 'A-Z' 'a-z'`"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
unset IFS
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_data_darwin() {
|
||||||
|
vendor_id="`/usr/sbin/sysctl -n machdep.cpu.vendor`"
|
||||||
|
cpu_family="`/usr/sbin/sysctl -n machdep.cpu.family`"
|
||||||
|
cpu_model="`/usr/sbin/sysctl -n machdep.cpu.model`"
|
||||||
|
flags="`/usr/sbin/sysctl -n machdep.cpu.features | tr 'A-Z' 'a-z'`"
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_data() {
|
||||||
|
# Default values
|
||||||
|
vendor_id="Unset"
|
||||||
|
cpu_family="-1"
|
||||||
|
cpu_model="-1"
|
||||||
|
flags=""
|
||||||
|
if [ "`uname`" = "Linux" ]; then
|
||||||
|
read_cpu_data_linux
|
||||||
|
elif [ "`uname`" = "FreeBSD" ]; then
|
||||||
|
read_cpu_data_freebsd
|
||||||
|
elif [ "`uname | sed 's/\(CYGWIN\).*/\1/'`" = "CYGWIN" ]; then
|
||||||
|
read_cpu_data_linux
|
||||||
|
elif [ "`uname`" = "Darwin" ]; then
|
||||||
|
read_cpu_data_darwin
|
||||||
|
else
|
||||||
|
echo "Error: `uname` is not a supported operating system"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_data
|
||||||
|
|
||||||
|
if [ "$vendor_id" = "AuthenticAMD" ]; then
|
||||||
|
if [ $cpu_family -eq 4 ]; then
|
||||||
|
_CFLAGS="-march=i486"
|
||||||
|
elif [ $cpu_family -eq 5 ]; then
|
||||||
|
if [ $cpu_model -lt 4 ]; then
|
||||||
|
_CFLAGS="-march=pentium"
|
||||||
|
elif [ \( $cpu_model -eq 6 \) -o \( $cpu_model -eq 7 \) ]; then
|
||||||
|
_CFLAGS="-march=k6"
|
||||||
|
elif [ \( $cpu_model -eq 8 \) -o \( $cpu_model -eq 12 \) ]; then
|
||||||
|
line="k6-2 k6"
|
||||||
|
elif [ \( $cpu_model -eq 9 \) -o \( $cpu_model -eq 13 \) ]; then
|
||||||
|
line="k6-3 k6-2 k6"
|
||||||
|
fi
|
||||||
|
elif [ $cpu_family -eq 6 ]; then
|
||||||
|
if [ $cpu_model -le 3 ]; then
|
||||||
|
line="athlon k6-3 k6-2 k6"
|
||||||
|
elif [ $cpu_model -eq 4 ]; then
|
||||||
|
line="athlon-tbird athlon k6-3 k6-2 k6"
|
||||||
|
elif [ $cpu_model -ge 6 ]; then #athlon-{4,xp,mp}
|
||||||
|
line="athlon-4 athlon k6-3 k6-2 k6"
|
||||||
|
fi
|
||||||
|
elif [ $cpu_family -eq 15 ]; then #k8,opteron,athlon64,athlon-fx
|
||||||
|
line="k8 athlon-4 athlon k6-3 k6-2 k6"
|
||||||
|
elif [ $cpu_family -eq 16 ]; then #barcelona,amdfam10
|
||||||
|
line="amdfam10 k8 athlon-4 athlon k6-3 k6-2 k6"
|
||||||
|
fi
|
||||||
|
elif [ "$vendor_id" = "CentaurHauls" ]; then
|
||||||
|
if [ $cpu_family -eq 5 ]; then
|
||||||
|
if [ $cpu_model -eq 4 ]; then
|
||||||
|
line="winchip-c6 pentium"
|
||||||
|
elif [ $cpu_model -eq 8 ]; then
|
||||||
|
line="winchip2 winchip-c6 pentium"
|
||||||
|
elif [ $cpu_model -ge 9 ]; then
|
||||||
|
line="winchip2 winchip-c6 pentium" #actually winchip3 but gcc doesn't support this currently
|
||||||
|
fi
|
||||||
|
elif [ $cpu_family -eq 6 ]; then
|
||||||
|
if echo "$flags" | grep -q cmov; then
|
||||||
|
fallback=pentiumpro
|
||||||
|
else
|
||||||
|
fallback=pentium #gcc incorrectly assumes i686 always has cmov
|
||||||
|
fi
|
||||||
|
if [ $cpu_model -eq 6 ]; then
|
||||||
|
_CFLAGS="-march=pentium" # ? Cyrix 3 (samuel)
|
||||||
|
elif [ $cpu_model -eq 7 ] || [ $cpu_model -eq 8 ]; then
|
||||||
|
line="c3 winchip2 winchip-c6 $fallback"
|
||||||
|
elif [ $cpu_model -ge 9 ]; then
|
||||||
|
line="c3-2 c3 winchip2 winchip-c6 $fallback"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "$vendor_id" = "GenuineIntel" ]; then
|
||||||
|
if [ $cpu_family -eq 3 ]; then
|
||||||
|
_CFLAGS="-march=i386"
|
||||||
|
elif [ $cpu_family -eq 4 ]; then
|
||||||
|
_CFLAGS="-march=i486"
|
||||||
|
elif [ $cpu_family -eq 5 ]; then
|
||||||
|
if [ $cpu_model -ne 4 ]; then
|
||||||
|
_CFLAGS="-march=pentium"
|
||||||
|
else
|
||||||
|
line="pentium-mmx pentium" #No overlap with other vendors
|
||||||
|
fi
|
||||||
|
elif [ $cpu_family -eq 6 ]; then
|
||||||
|
if [ \( $cpu_model -eq 0 \) -o \( $cpu_model -eq 1 \) ]; then
|
||||||
|
_CFLAGS="-march=pentiumpro"
|
||||||
|
elif [ \( $cpu_model -ge 3 \) -a \( $cpu_model -le 6 \) ]; then #4=TM5600 at least
|
||||||
|
line="pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
elif [ \( $cpu_model -eq 9 \) -o \( $cpu_model -eq 13 \) ]; then #centrino
|
||||||
|
line="pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
elif [ $cpu_model -eq 14 ]; then #Core
|
||||||
|
line="prescott pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
elif [ $cpu_model -eq 15 ]; then #Core 2
|
||||||
|
line="core2 pentium-m pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
elif [ \( $cpu_model -ge 7 \) -a \( $cpu_model -le 11 \) ]; then
|
||||||
|
line="pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
fi
|
||||||
|
elif [ $cpu_family -eq 15 ]; then
|
||||||
|
line="pentium4 pentium3 pentium2 pentiumpro pentium-mmx pentium i486 i386"
|
||||||
|
if [ $cpu_model -ge 3 ]; then
|
||||||
|
line="prescott $line"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Unknown CPU Vendor: $vendor_id"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$_CFLAGS" ] && _CFLAGS="-march=`try_line "$line"`"
|
||||||
|
|
||||||
|
#SSE is not used for floating point by default in gcc 32 bit
|
||||||
|
#so turn that on here.
|
||||||
|
if echo "$flags" | grep -q "sse"; then
|
||||||
|
if try_gcc_options "-mfpmath=sse"; then #gcc >= 3.1
|
||||||
|
_CFLAGS="$_CFLAGS -mfpmath=sse"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#The SSE options are mostly selected automatically
|
||||||
|
#when a particular march option is selected.
|
||||||
|
#There are a few exceptions unfortunately, which we handle here.
|
||||||
|
#Note the sse instruction lines are:
|
||||||
|
# intel: [sse4.2] [sse4.1] ssse3 sse3 sse2 sse ...
|
||||||
|
# amd: [sse5] sse4a [sse3] sse2 sse ...
|
||||||
|
# The bracketed ones are only available on some cpus
|
||||||
|
# in a particular family and so need to be added explicitly.
|
||||||
|
if echo "$_CFLAGS" | grep -q "amdfam10"; then
|
||||||
|
if echo "$flags" | grep -q "sse5"; then
|
||||||
|
if try_gcc_options "-msse5"; then #gcc >= 4.3
|
||||||
|
_CFLAGS="$_CFLAGS -msse5"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif echo "$_CFLAGS" | grep -E -q "(k8|c3-2)"; then
|
||||||
|
if echo "$flags" | grep -E -q "(sse3|pni)"; then
|
||||||
|
if try_gcc_options "-msse3"; then #gcc >= 3.3.3
|
||||||
|
_CFLAGS="$_CFLAGS -msse3"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif echo "$_CFLAGS" | grep -q "core2"; then
|
||||||
|
if echo "$flags" | grep -q "sse4_2"; then
|
||||||
|
if try_gcc_options "-msse4"; then #gcc >= 4.3
|
||||||
|
_CFLAGS="$_CFLAGS -msse4"
|
||||||
|
fi
|
||||||
|
elif echo "$flags" | grep -q "sse4_1"; then
|
||||||
|
if try_gcc_options "-msse4.1"; then #gcc >= 4.3
|
||||||
|
_CFLAGS="$_CFLAGS -msse4.1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$m32$_CFLAGS"
|
||||||
369
ide/main.nim
Executable file
369
ide/main.nim
Executable file
|
|
@ -0,0 +1,369 @@
|
||||||
|
|
||||||
|
import glib2, gtk2, libglade2
|
||||||
|
|
||||||
|
proc on_window_destroy(obj: PGtkObject, data: pointer) {.exportc, cdecl.} =
|
||||||
|
gtk_main_quit()
|
||||||
|
|
||||||
|
const
|
||||||
|
GuiTemplate = "/media/hda4/nimrod/ide/nimide.glade"
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyTextEditor = record
|
||||||
|
window: PGtkWindow
|
||||||
|
statusbar: PGtkStatusBar
|
||||||
|
textview: PGtkTextview
|
||||||
|
statusbarContextId: int
|
||||||
|
filename: string
|
||||||
|
|
||||||
|
proc error_message(msg: string) =
|
||||||
|
var
|
||||||
|
dialog: PGtkDialog
|
||||||
|
dialog = GTK_DIALOG(gtk_message_dialog_new(nil,
|
||||||
|
GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg))
|
||||||
|
|
||||||
|
gtk_window_set_title(dialog, "Error!")
|
||||||
|
gtk_dialog_run(dialog)
|
||||||
|
gtk_widget_destroy(dialog)
|
||||||
|
|
||||||
|
|
||||||
|
proc get_open_filename(e: TMyTextEditor): string =
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = gtk_file_chooser_dialog_new("Open File...", e.window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
|
||||||
|
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
result = $gtk_file_chooser_get_filename(chooser)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
|
|
||||||
|
proc get_save_filename(e: TMyTextEditor): string =
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = gtk_file_chooser_dialog_new("Save File...", e.window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
|
||||||
|
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
result = $gtk_file_chooser_get_filename(chooser)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
|
proc load_file(e: var TMyTextEditor, filename: string) =
|
||||||
|
var
|
||||||
|
err: ptr GError
|
||||||
|
status: cstring
|
||||||
|
text: cstring
|
||||||
|
result: bool
|
||||||
|
buffer: PGtkTextBuffer
|
||||||
|
gtk_statusbar_push(e.statusbar, e.statusbar_context_id, "Loading...")
|
||||||
|
while gtk_events_pending(): gtk_main_iteration()
|
||||||
|
|
||||||
|
# get the file contents
|
||||||
|
result = g_file_get_contents(filename, addr(text), nil, addr(err))
|
||||||
|
if not result:
|
||||||
|
error_message("Cannot load file")
|
||||||
|
g_error_free(err)
|
||||||
|
|
||||||
|
# disable the text view while loading the buffer with the text
|
||||||
|
gtk_widget_set_sensitive(e.text_view, false)
|
||||||
|
buffer = gtk_text_view_get_buffer(e.text_view)
|
||||||
|
gtk_text_buffer_set_text(buffer, text, -1)
|
||||||
|
gtk_text_buffer_set_modified(buffer, false)
|
||||||
|
gtk_widget_set_sensitive(e.text_view, true)
|
||||||
|
g_free(text)
|
||||||
|
|
||||||
|
e.filename = filename
|
||||||
|
gtk_statusbar_pop(e.statusbar, e.statusbar_context_id)
|
||||||
|
reset_default_status(e)
|
||||||
|
|
||||||
|
proc write_file(e: var TMyTextEditor, filename: string) =
|
||||||
|
var
|
||||||
|
err: ptr GError
|
||||||
|
status: cstring
|
||||||
|
text: cstring
|
||||||
|
result: bool
|
||||||
|
buffer: PGtkTextBuffer
|
||||||
|
start, ende: TGtkTextIter
|
||||||
|
# add Saving message to status bar and ensure GUI is current
|
||||||
|
gtk_statusbar_push(e.statusbar, e.statusbar_context_id, "Saving....")
|
||||||
|
while gtk_events_pending(): gtk_main_iteration()
|
||||||
|
|
||||||
|
# disable text view and get contents of buffer
|
||||||
|
gtk_widget_set_sensitive(editor->text_view, FALSE)
|
||||||
|
buffer = gtk_text_view_get_buffer(e.text_view)
|
||||||
|
gtk_text_buffer_get_start_iter(buffer, start)
|
||||||
|
gtk_text_buffer_get_end_iter(buffer, ende)
|
||||||
|
text = gtk_text_buffer_get_text(buffer, start, ende, FALSE)
|
||||||
|
gtk_text_buffer_set_modified(buffer, false)
|
||||||
|
gtk_widget_set_sensitive(e.text_view, true)
|
||||||
|
# set the contents of the file to the text from the buffer
|
||||||
|
if filename != "":
|
||||||
|
result = g_file_set_contents(filename, text, -1, addr(err))
|
||||||
|
else:
|
||||||
|
result = g_file_set_contents(editor->filename, text, -1, addr(err))
|
||||||
|
if not result:
|
||||||
|
error_message("cannot save")
|
||||||
|
g_error_free(err)
|
||||||
|
g_free(text)
|
||||||
|
if filename != "":
|
||||||
|
e.filename = filename
|
||||||
|
gtk_statusbar_pop(e.statusbar, e.statusbar_context_id)
|
||||||
|
reset_default_status(editor)
|
||||||
|
|
||||||
|
|
||||||
|
proc initApp(e: var TMyTextEditor) =
|
||||||
|
var
|
||||||
|
builder: PGladeXML
|
||||||
|
window: PGtkWidget
|
||||||
|
fontDesc: PPangoFontDescription
|
||||||
|
id: int
|
||||||
|
builder = glade_xml_new(GuiTemplate, nil, nil)
|
||||||
|
if builder == nil:
|
||||||
|
error_message("cannot open: " & GuiTemplate)
|
||||||
|
quit(1)
|
||||||
|
# get the components:
|
||||||
|
e.window = GTK_WINDOW(glade_xml_get_widget(builder, "window"))
|
||||||
|
e.statusbar = GTK_STATUSBAR(glade_xml_get_widget(builder, "statusbar"))
|
||||||
|
e.textview = GTK_TEXTVIEW(glade_xml_get_widget(builder, "textview"))
|
||||||
|
|
||||||
|
# connect the signal handlers:
|
||||||
|
glade_xml_signal_connect(builder, "on_window_destroy",
|
||||||
|
cast[TGCallback](on_window_destroy))
|
||||||
|
|
||||||
|
font_desc = pango_font_description_from_string("monospace 10")
|
||||||
|
gtk_widget_modify_font(e.textview, font_desc)
|
||||||
|
pango_font_description_free(font_desc)
|
||||||
|
gtk_window_set_default_icon_name(GTK_STOCK_EDIT)
|
||||||
|
|
||||||
|
id = gtk_statusbar_get_context_id(e.statusbar, "Nimrod IDE")
|
||||||
|
e.statusbarContextId = id
|
||||||
|
reset_default_status(e)
|
||||||
|
|
||||||
|
e.filename = ""
|
||||||
|
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
var
|
||||||
|
editor: TMyTextEditor
|
||||||
|
|
||||||
|
gtk_nimrod_init()
|
||||||
|
initApp(editor)
|
||||||
|
gtk_widget_show(editor.window)
|
||||||
|
gtk_main()
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
proc reset_default_status(e: var TMyTextEditor)
|
||||||
|
gchar *file;
|
||||||
|
gchar *status;
|
||||||
|
|
||||||
|
if e.filename == "":
|
||||||
|
file = g_strdup("(UNTITLED)")
|
||||||
|
else:
|
||||||
|
file = g_path_get_basename(editor->filename)
|
||||||
|
|
||||||
|
status = g_strdup_printf("File: %s", file)
|
||||||
|
gtk_statusbar_pop(e.statusbar,
|
||||||
|
e.statusbar_context_id)
|
||||||
|
gtk_statusbar_push(e.statusbar,
|
||||||
|
e.statusbar_context_id, status)
|
||||||
|
g_free(status)
|
||||||
|
g_free(file)
|
||||||
|
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
check_for_save(e: var TMyTextEditor)
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
if (gtk_text_buffer_get_modified (buffer) == TRUE)
|
||||||
|
{
|
||||||
|
GtkWidget *dialog;
|
||||||
|
const gchar *msg = "Do you want to save the changes you have made?";
|
||||||
|
dialog = gtk_message_dialog_new (NULL,
|
||||||
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_MESSAGE_QUESTION,
|
||||||
|
GTK_BUTTONS_YES_NO,
|
||||||
|
msg);
|
||||||
|
gtk_window_set_title (GTK_WINDOW (dialog), "Save?");
|
||||||
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_NO)
|
||||||
|
{
|
||||||
|
ret = FALSE;
|
||||||
|
} else ret = TRUE;
|
||||||
|
gtk_widget_destroy (dialog);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
When the window is requested to be closed, we need to check if they have
|
||||||
|
unsaved work. We use this callback to prompt the user to save their work before
|
||||||
|
they exit the application. From the "delete-event" signal, we can choose to
|
||||||
|
effectively cancel the close based on the value we return.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
on_window_delete_event(GtkWidget *widget, GdkEvent *event,
|
||||||
|
TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
if (check_for_save (editor) == TRUE)
|
||||||
|
on_save_menu_item_activate (NULL, editor);
|
||||||
|
return FALSE; /* propogate event */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'New' menu. We need to prompt for save if the
|
||||||
|
file has been modified, and then delete the buffer and clear the modified flag.
|
||||||
|
*/
|
||||||
|
void on_new_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
|
||||||
|
if (check_for_save (editor) == TRUE)
|
||||||
|
{
|
||||||
|
on_save_menu_item_activate (NULL, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear editor for a new file */
|
||||||
|
editor->filename = NULL;
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
gtk_text_buffer_set_text (buffer, "", -1);
|
||||||
|
gtk_text_buffer_set_modified (buffer, FALSE);
|
||||||
|
|
||||||
|
reset_default_status (editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Open' menu. We need to prompt for save if the
|
||||||
|
file has been modified, allow the user to choose a file to open, and then call
|
||||||
|
load_file() on that file.
|
||||||
|
*/
|
||||||
|
void on_open_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
gchar *filename;
|
||||||
|
|
||||||
|
if (check_for_save (editor) == TRUE)
|
||||||
|
{
|
||||||
|
on_save_menu_item_activate (NULL, editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = get_open_filename (editor);
|
||||||
|
if (filename != NULL) load_file (editor, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Save' menu. We need to allow the user to choose
|
||||||
|
a file to save if it's an untitled document, and then call write_file() on that
|
||||||
|
file.
|
||||||
|
*/
|
||||||
|
void on_save_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
gchar *filename;
|
||||||
|
|
||||||
|
if (editor->filename == NULL)
|
||||||
|
{
|
||||||
|
filename = get_save_filename (editor);
|
||||||
|
if (filename != NULL) write_file (editor, filename);
|
||||||
|
}
|
||||||
|
else write_file (editor, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Save As' menu. We need to allow the user to
|
||||||
|
choose a file to save and then call write_file() on that file.
|
||||||
|
*/
|
||||||
|
void on_save_as_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
gchar *filename;
|
||||||
|
|
||||||
|
filename = get_save_filename (editor);
|
||||||
|
if (filename != NULL) write_file (editor, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Quit' menu. We need to prompt for save if the
|
||||||
|
file has been modified and then break out of the GTK+ main loop.
|
||||||
|
*/
|
||||||
|
void on_quit_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
if (check_for_save (editor) == TRUE)
|
||||||
|
{
|
||||||
|
on_save_menu_item_activate (NULL, editor);
|
||||||
|
}
|
||||||
|
gtk_main_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Cut' menu.
|
||||||
|
*/
|
||||||
|
void on_cut_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkClipboard *clipboard;
|
||||||
|
|
||||||
|
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Copy' menu.
|
||||||
|
*/
|
||||||
|
void on_copy_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkClipboard *clipboard;
|
||||||
|
|
||||||
|
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
gtk_text_buffer_copy_clipboard (buffer, clipboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Paste' menu.
|
||||||
|
*/
|
||||||
|
void on_paste_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkClipboard *clipboard;
|
||||||
|
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Called when the user clicks the 'Delete' menu.
|
||||||
|
*/
|
||||||
|
void on_delete_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
|
||||||
|
gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_about_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
|
||||||
|
{
|
||||||
|
static const gchar * const authors[] = {
|
||||||
|
"Micah Carrick <email@micahcarrick.com>",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const gchar copyright[] = "Copyright \xc2\xa9 2008 Andreas Rumpf";
|
||||||
|
static const gchar comments[] = "GTK+ and Glade3 GUI Programming Tutorial";
|
||||||
|
gtk_show_about_dialog (e.window,
|
||||||
|
"authors", authors,
|
||||||
|
"comments", comments,
|
||||||
|
"copyright", copyright,
|
||||||
|
"version", "0.1",
|
||||||
|
"website", "http://www.micahcarrick.com",
|
||||||
|
"program-name", "GTK+ Text Editor",
|
||||||
|
"logo-icon-name", GTK_STOCK_EDIT, nil)
|
||||||
|
}
|
||||||
175
ide/nimide.glade
Executable file
175
ide/nimide.glade
Executable file
|
|
@ -0,0 +1,175 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||||
|
<!--Generated with glade3 3.4.2 on Sat Jun 21 14:12:42 2008 -->
|
||||||
|
<glade-interface>
|
||||||
|
<widget class="GtkWindow" id="window">
|
||||||
|
<property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
|
||||||
|
<signal name="destroy" handler="on_window_destroy" object="destroy"/>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkVBox" id="mainvbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuBar" id="menubar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Datei</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menu1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="new_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-new</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="open_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-open</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="save_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-save</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="save_as_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-save-as</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="quit_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-quit</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Bearbeiten</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menu2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="cut_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-cut</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="copy_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-copy</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="paste_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-paste</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="delete_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-delete</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="menuitem4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">_Hilfe</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenu" id="menu3">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkImageMenuItem" id="about_menu_item">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">gtk-about</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkScrolledWindow" id="scrolledwindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
|
||||||
|
<property name="border_width">1</property>
|
||||||
|
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||||
|
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkTextView" id="textview">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="left_margin">2</property>
|
||||||
|
<property name="right_margin">2</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkStatusbar" id="statusbar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
</glade-interface>
|
||||||
101
install.txt
Executable file
101
install.txt
Executable file
|
|
@ -0,0 +1,101 @@
|
||||||
|
Note: Installation does not work yet - you have to bootstrap. Play with the
|
||||||
|
``koch.py`` script to compile the compiler.
|
||||||
|
Compile the compiler::
|
||||||
|
|
||||||
|
python koch.py nim
|
||||||
|
|
||||||
|
To bootstrap (does not work yet)::
|
||||||
|
|
||||||
|
python koch.py boot
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Note:
|
||||||
|
A C compiler is required - knowledge of C is not!
|
||||||
|
|
||||||
|
Installation on UNIX
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The GNU C Compiler is fully supported, other compilers may work. The C compiler
|
||||||
|
should be in your ``$PATH`` (most likely the case). Note that some Linux
|
||||||
|
distributions do not ship with a C compiler preinstalled - then you have to
|
||||||
|
install one.
|
||||||
|
|
||||||
|
After you have made sure that a C compiler is available, install Nimrod
|
||||||
|
by downloading the appropriate ``.zip`` file and extracting it to a
|
||||||
|
directory of your choice. The Nimrod Compiler will stay in this
|
||||||
|
directory; do not use a temporary one! Good choices are ``/opt/nimrod`` or -
|
||||||
|
if you don't have root access - ``~/programs/nimrod``.
|
||||||
|
Then run the following command::
|
||||||
|
|
||||||
|
python koch.py install
|
||||||
|
|
||||||
|
Unlike other software, Nimrod does not distribute its files over the whole file
|
||||||
|
hierarchy. This has the advantage that you can deinstall it by just deleting
|
||||||
|
its folder. The disadvantage is that you have to add it to your ``PATH``
|
||||||
|
manually. The alternative is to create a symbolic link in ``/usr/bin``::
|
||||||
|
|
||||||
|
[sudo] ln -s $your_install_dir/bin/nimrod /usr/bin/nimrod
|
||||||
|
|
||||||
|
|
||||||
|
Installation on the Macintosh
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Only MacOS X is supported.
|
||||||
|
Since MacOS X is UNIX based too, it works like the installation on UNIX. You
|
||||||
|
need to install Apple's developer's tools for the GNU Compiler Collection
|
||||||
|
though.
|
||||||
|
|
||||||
|
|
||||||
|
Installation on Windows
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Windows does not ship with a C compiler; you have to install one. The
|
||||||
|
following C compilers are supported under Windows:
|
||||||
|
|
||||||
|
- | Digital Mars C++
|
||||||
|
| http://www.digitalmars.com/download/freecompiler.html
|
||||||
|
|
||||||
|
- | Watcom C++
|
||||||
|
| http://www.openwatcom.org/ftp/
|
||||||
|
|
||||||
|
- | Borland C++ (5.5 or above; including Borland C++Builder)
|
||||||
|
| http://www.borland.com/downloads/download_cbuilder.html
|
||||||
|
| (Download the package under "compiler" - this requires registration though.)
|
||||||
|
|
||||||
|
- | Microsoft's Visual C++
|
||||||
|
| http://msdn.microsoft.com/visualc
|
||||||
|
| (You may need the SDK too - but not the full one: Essential are only
|
||||||
|
the win32api header files and import libraries.)
|
||||||
|
|
||||||
|
- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
|
||||||
|
| http://www.mingw.org/download.shtml
|
||||||
|
|
||||||
|
- | LLVM with GNU C/C++ frontend
|
||||||
|
| http://llvm.org/releases/download.html#2.2
|
||||||
|
|
||||||
|
- | Pelles C Compiler
|
||||||
|
| http://www.smorgasbordet.com/pellesc
|
||||||
|
|
||||||
|
- | Lcc-win32
|
||||||
|
| http://www.cs.virginia.edu/~lcc-win32
|
||||||
|
|
||||||
|
All of the above compilers are available for free!
|
||||||
|
(The first three are the easiest to install.) If you want a small download,
|
||||||
|
choose Digital Mars C++ -- it is easy to install and only about 3 MB.
|
||||||
|
If you want the highest possible performance, go for Microsoft's Visual C++ or
|
||||||
|
LLVM.
|
||||||
|
|
||||||
|
After you have made sure that a C compiler is available, install
|
||||||
|
Nimrod by downloading the appropriate .zip file and extracting it to a
|
||||||
|
directory of your choice. The Nimrod Compiler will stay in this
|
||||||
|
directory; do not use a temporary one! Then run ``config.exe`` in the
|
||||||
|
``bin`` subdirectory. Choose your C compiler and press ``OK``. You should
|
||||||
|
add Nimrod to your ``$PATH``.
|
||||||
|
|
||||||
|
Alternatively, you can install Nimrod with the ``koch.py`` script just like
|
||||||
|
in the UNIX installation instructions.
|
||||||
|
|
||||||
|
Nimrod does not use the Registry and can be removed by just deleting its folder.
|
||||||
982
koch.py
Executable file
982
koch.py
Executable file
|
|
@ -0,0 +1,982 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
## ##
|
||||||
|
## Build script of the Nimrod Compiler ##
|
||||||
|
## (c) 2008 Andreas Rumpf ##
|
||||||
|
## ##
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import os, os.path, sys, re, zipfile, filecmp, shutil, cPickle, time
|
||||||
|
import string, getopt, textwrap, glob, shutil, getopt, string
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[0] >= 3: # this script does not work with Python 3.0
|
||||||
|
sys.exit("wrong python version: use Python 2.x")
|
||||||
|
|
||||||
|
from kochmod import *
|
||||||
|
|
||||||
|
# --------------------- constants ----------------------------------------
|
||||||
|
|
||||||
|
CFLAGS = "" # modify to set flags to the first compilation step
|
||||||
|
|
||||||
|
NIMROD_VERSION = '0.2.1'
|
||||||
|
# This string contains Nimrod's version. It is the only place
|
||||||
|
# where the version needs to be updated. The rest is done by
|
||||||
|
# the build process automatically. It is replaced **everywhere**
|
||||||
|
# automatically!
|
||||||
|
# Format is: Major.Minor.Patch
|
||||||
|
# Major part: plan is to use number 1 for the first version that is stable;
|
||||||
|
# higher versions may be incompatible with previous versions
|
||||||
|
# Minor part: incremented if new features are added (but is completely
|
||||||
|
# backwards-compatible)
|
||||||
|
# Patch level: is increased for every patch
|
||||||
|
|
||||||
|
|
||||||
|
EXPLAIN = True
|
||||||
|
force = False
|
||||||
|
|
||||||
|
INNOSETUP = r"c:\programme\innosetup5\iscc.exe /Q "
|
||||||
|
ADV_SETUP = r"C:\Programme\AdvancedInstaller6.1\AdvancedInstaller.com " \
|
||||||
|
r"/build %s -force"
|
||||||
|
PYINSTALLER = r"C:\Eigenes\DownLoad\Python\pyinstaller-1.3"
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def ask():
|
||||||
|
return sys.stdin.readline().strip("\t \n\r\f").lower()
|
||||||
|
|
||||||
|
def CogRule(name, filename, dependson):
|
||||||
|
def processCog():
|
||||||
|
from cogapp import Cog
|
||||||
|
ret = Cog().main([sys.argv[0], "-r", Path(filename)])
|
||||||
|
return ret
|
||||||
|
|
||||||
|
c = Changed(name, filename + " " + dependson, EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
if processCog() == 0:
|
||||||
|
c.update(filename)
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
_nim_exe = os.path.join(os.getcwd(), "bin", ExeExt("nim"))
|
||||||
|
_output_obj = os.path.join(os.getcwd(), "obj")
|
||||||
|
FPC_CMD = (r"fpc -Cs16777216 -gl -bl -Crtoi -Sgidh -vw -Se1 -o%s "
|
||||||
|
r"-FU%s %s") % (_nim_exe, _output_obj,
|
||||||
|
os.path.join(os.getcwd(), "nim", "nimrod.pas"))
|
||||||
|
|
||||||
|
def buildRod(options):
|
||||||
|
Exec("nim compile --compile:build/platdef.c %s rod/nimrod" % options)
|
||||||
|
Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
|
||||||
|
|
||||||
|
def cmd_nim():
|
||||||
|
CogRule("nversion", "nim/nversion.pas", "koch.py")
|
||||||
|
CogRule("msgs", "nim/msgs.pas", "data/messages.yml")
|
||||||
|
CogRule("ast", "nim/ast.pas", "koch.py data/magic.yml data/ast.yml")
|
||||||
|
CogRule("scanner", "nim/scanner.pas", "data/keywords.txt")
|
||||||
|
CogRule("paslex", "nim/paslex.pas", "data/pas_keyw.yml")
|
||||||
|
CogRule("wordrecg", "nim/wordrecg.pas", "data/keywords.txt")
|
||||||
|
CogRule("commands", "nim/commands.pas",
|
||||||
|
"data/basicopt.txt data/advopt.txt data/changes.txt")
|
||||||
|
c = Changed("nim", Glob("nim/*.pas"),
|
||||||
|
EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
Exec(FPC_CMD)
|
||||||
|
if Exists(ExeExt("bin/nim")):
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
def cmd_rod(options):
|
||||||
|
cmd_nim()
|
||||||
|
prereqs = Glob("lib/*.nim") + Glob("rod/*.nim") + [
|
||||||
|
"lib/nimbase.h", "lib/dlmalloc.c", "lib/dlmalloc.h",
|
||||||
|
"config/nimrod.cfg"]
|
||||||
|
c = Changed("rod", prereqs, EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
buildRod(options)
|
||||||
|
if Exists(ExeExt("bin/nimrod")):
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
# ------------------- constants -----------------------------------------------
|
||||||
|
|
||||||
|
HELP = """\
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
| Maintenance script for Nimrod |
|
||||||
|
| Version %s|
|
||||||
|
| (c) 2008 Andreas Rumpf |
|
||||||
|
+-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
koch.py [options] command [options for command]
|
||||||
|
Options:
|
||||||
|
--force, -f, -B, -b force rebuild
|
||||||
|
--help, -h shows this help and quits
|
||||||
|
Possible Commands:
|
||||||
|
install [options] installs the Nimrod Compiler: options
|
||||||
|
are --cc=<compile command>, --ld=<link command>
|
||||||
|
nim builds the Pascal version of Nimrod
|
||||||
|
rod [options] builds the Nimrod version of Nimrod (with options)
|
||||||
|
installer builds the installer (needs Inno Setup 5 on Windows)
|
||||||
|
configure configures the environment for developing Nimrod
|
||||||
|
doc builds the documentation in HTML
|
||||||
|
clean cleans Nimrod project; removes generated files
|
||||||
|
dist produces a distribution as
|
||||||
|
nimrod_$target_$version.zip
|
||||||
|
boot [options] bootstraps with given command line options
|
||||||
|
tests [options] runs the complete testsuite (with options)
|
||||||
|
rodsrc generates Nimrod version from Pascal version
|
||||||
|
web generates the website (requires Cheetah)
|
||||||
|
""" % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)))
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
if len(args) == 0:
|
||||||
|
print HELP
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
|
while args[i].startswith("-"):
|
||||||
|
a = args[i]
|
||||||
|
if a in ("--force", "-f", "-B", "-b"):
|
||||||
|
global force
|
||||||
|
force = True
|
||||||
|
elif a in ("-h", "--help", "-?"):
|
||||||
|
print HELP
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
Error("illegal option: " + a)
|
||||||
|
i += 1
|
||||||
|
cmd = args[i]
|
||||||
|
if cmd == "rod": cmd_rod(" ".join(args[i+1:]))
|
||||||
|
elif cmd == "nim": cmd_nim()
|
||||||
|
elif cmd == "installer": cmd_installer()
|
||||||
|
elif cmd == "configure": cmd_configure()
|
||||||
|
elif cmd == "doc": cmd_doc()
|
||||||
|
elif cmd == "clean": cmd_clean()
|
||||||
|
elif cmd == "dist": cmd_dist()
|
||||||
|
elif cmd == "boot": cmd_boot(" ".join(args[i+1:]))
|
||||||
|
elif cmd == "tests": cmd_tests(" ".join(args[i+1:]))
|
||||||
|
elif cmd == "install": cmd_install(args[i+1:])
|
||||||
|
elif cmd == "rodsrc": cmd_rodsrc()
|
||||||
|
elif cmd == "web": cmd_web()
|
||||||
|
else: Error("illegal command: " + cmd)
|
||||||
|
|
||||||
|
# -------------------------- bootstrap ----------------------------------------
|
||||||
|
|
||||||
|
def cmd_rodsrc():
|
||||||
|
"converts the src/*.pas files into Nimrod syntax"
|
||||||
|
PAS_FILES_BLACKLIST = """nsystem nmath nos ntime strutils""".split()
|
||||||
|
CMD = "nim boot --skip_proj_cfg -o:rod/%s.nim nim/%s"
|
||||||
|
cmd_nim()
|
||||||
|
result = False
|
||||||
|
for fi in Glob("nim/*.pas"):
|
||||||
|
f = FilenameNoExt(fi)
|
||||||
|
if f in PAS_FILES_BLACKLIST: continue
|
||||||
|
c = Changed(f+"__rodsrc", fi, EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
Exec(CMD % (f, f+".pas"))
|
||||||
|
Exec("nim parse rod/%s.nim" % f)
|
||||||
|
c.success()
|
||||||
|
result = True
|
||||||
|
return result
|
||||||
|
|
||||||
|
def cmd_boot(args):
|
||||||
|
writePlatdefC(getNimrodPath())
|
||||||
|
d = detect("fpc -h")
|
||||||
|
if d:
|
||||||
|
Echo("'%s' detected" % d)
|
||||||
|
cmd_nim()
|
||||||
|
compiler = "nim"
|
||||||
|
else:
|
||||||
|
Warn("Free Pascal is not installed; skipping Pascal step")
|
||||||
|
cmd_install(args)
|
||||||
|
compiler = "nimrod"
|
||||||
|
|
||||||
|
cmd_rodsrc() # regenerate nimrod version of the files
|
||||||
|
|
||||||
|
# move the new executable to bin directory (is done by cmd_rod())
|
||||||
|
# use the new executable to compile the files in the bootstrap directory:
|
||||||
|
Exec("%s compile --compile:build/platdef.c %s rod/nimrod.nim" %
|
||||||
|
(compiler, args))
|
||||||
|
# move the new executable to bin directory:
|
||||||
|
Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
|
||||||
|
# compile again and compare:
|
||||||
|
Exec("nimrod compile --compile:build/platdef.c %s rod/nimrod.nim" % args)
|
||||||
|
|
||||||
|
# check if the executables are the same (they should!):
|
||||||
|
if filecmp.cmp(Path(ExeExt("rod/nimrod")),
|
||||||
|
Path(ExeExt("bin/nimrod"))):
|
||||||
|
Echo("files are equal: everything seems fine!")
|
||||||
|
else:
|
||||||
|
Warn("files are not equal: cycle once again...")
|
||||||
|
# move the new executable to bin directory:
|
||||||
|
Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
|
||||||
|
# use the new executable to compile Nimrod:
|
||||||
|
Exec("nimrod compile %s rod/nimrod.nim" % args)
|
||||||
|
if filecmp.cmp(Path(ExeExt("rod/nimrod")),
|
||||||
|
Path(ExeExt("bin/nimrod"))):
|
||||||
|
Echo("files are equal: everything seems fine!")
|
||||||
|
else:
|
||||||
|
Error("files are still not equal")
|
||||||
|
|
||||||
|
# ------------------ web ------------------------------------------------------
|
||||||
|
|
||||||
|
def buildDoc(destPath):
|
||||||
|
DOC = "endb intern lib manual nimrodc tutorial overview".split()
|
||||||
|
SRCDOC = "system os strutils base/regexprs math complex times".split()
|
||||||
|
# call nim for the documentation:
|
||||||
|
for d in DOC:
|
||||||
|
Exec("nim rst2html --putenv:nimrodversion=%s -o:%s/%s.html "
|
||||||
|
"--index=%s/theindex doc/%s" %
|
||||||
|
(NIMROD_VERSION, destPath, d, destPath, d))
|
||||||
|
for d in SRCDOC:
|
||||||
|
Exec("nim doc --putenv:nimrodversion=%s -o:%s/%s.html "
|
||||||
|
"--index=%s/theindex lib/%s" %
|
||||||
|
(NIMROD_VERSION, destPath, FilenameNoExt(d), destPath, d))
|
||||||
|
Exec("nim rst2html -o:%s/theindex.html %s/theindex" % (destPath, destPath))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_web():
|
||||||
|
import Cheetah.Template
|
||||||
|
TABS = [ # Our tabs: (Menu entry, filename)
|
||||||
|
("home", "index"),
|
||||||
|
("documentation", "documentation"),
|
||||||
|
("download", "download"),
|
||||||
|
("FAQ", "question"),
|
||||||
|
("links", "links")
|
||||||
|
]
|
||||||
|
TEMPLATE_FILE = "web/sunset.tmpl"
|
||||||
|
#CMD = "rst2html.py --template=web/docutils.tmpl web/%s.txt web/%s.temp "
|
||||||
|
CMD = "nim rst2html --compileonly -o:web/%s.temp web/%s.txt"
|
||||||
|
|
||||||
|
c = Changed("web", Glob("web/*.txt") + [TEMPLATE_FILE, "koch.py"] +
|
||||||
|
Glob("doc/*.txt") + Glob("lib/*.txt") + Glob("lib/*.nim")+
|
||||||
|
Glob("config/*.cfg"),
|
||||||
|
EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
cmd_nim() # we need Nimrod for processing the documentation
|
||||||
|
Exec(CMD % ("news","news"))
|
||||||
|
newsText = file("web/news.temp").read()
|
||||||
|
for t in TABS:
|
||||||
|
Exec(CMD % (t[1],t[1]))
|
||||||
|
|
||||||
|
tmpl = Cheetah.Template.Template(file=TEMPLATE_FILE)
|
||||||
|
tmpl.content = file("web/%s.temp" % t[1]).read()
|
||||||
|
tmpl.news = newsText
|
||||||
|
tmpl.tab = t[1]
|
||||||
|
tmpl.tabs = TABS
|
||||||
|
tmpl.lastupdate = time.strftime("%Y-%m-%d %X", time.gmtime())
|
||||||
|
f = file("web/%s.html" % t[1], "w+")
|
||||||
|
f.write(str(tmpl))
|
||||||
|
f.close()
|
||||||
|
# remove temporaries:
|
||||||
|
Remove("web/news.temp")
|
||||||
|
for t in TABS: Remove("web/%s.temp" % t[1])
|
||||||
|
buildDoc("web")
|
||||||
|
if Exists("web/index.html"):
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
# ------------------ doc ------------------------------------------------------
|
||||||
|
|
||||||
|
def cmd_doc():
|
||||||
|
c = Changed("doc", ["koch.py"] +
|
||||||
|
Glob("doc/*.txt") + Glob("lib/*.txt") + Glob("lib/*.nim")+
|
||||||
|
Glob("config/*.cfg"),
|
||||||
|
EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
cmd_nim() # we need Nimrod for processing the documentation
|
||||||
|
buildDoc("doc")
|
||||||
|
if Exists("doc/overview.html"):
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def getVersion():
|
||||||
|
return NIMROD_VERSION
|
||||||
|
|
||||||
|
# ------------------------------ clean ----------------------------------------
|
||||||
|
|
||||||
|
CLEAN_EXT = "ppu o obj dcu ~pas ~inc ~dsk ~dpr map tds err bak pyc exe rod"
|
||||||
|
|
||||||
|
def cmd_clean(dir = "."):
|
||||||
|
extRegEx = re.compile("|".join([r".*\."+ x +"$" for x in CLEAN_EXT.split()]))
|
||||||
|
Remove("koch.dat")
|
||||||
|
for f in Glob("web/*.html"): Remove(f)
|
||||||
|
for f in Glob("doc/html/*.html"): Remove(f)
|
||||||
|
for f in Glob("doc/*.html"): Remove(f)
|
||||||
|
for f in Glob("rod/*.nim"): Remove(f) # remove generated source code
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(dir, topdown=False):
|
||||||
|
for name in files:
|
||||||
|
if (extRegEx.match(name)
|
||||||
|
or (root == "tests" and ('.' not in name))):
|
||||||
|
Remove(os.path.join(root, name))
|
||||||
|
for name in dirs:
|
||||||
|
if name == "rod_gen":
|
||||||
|
shutil.rmtree(path=os.path.join(root, name), ignore_errors=True)
|
||||||
|
|
||||||
|
# ----------------- distributions ---------------------------------------------
|
||||||
|
|
||||||
|
# Here are listed all files that should be included in the different
|
||||||
|
# distributions.
|
||||||
|
|
||||||
|
distlist = {
|
||||||
|
'common': (
|
||||||
|
"copying.txt",
|
||||||
|
"gpl.html",
|
||||||
|
"koch.py",
|
||||||
|
|
||||||
|
"lib/nimbase.h -> lib/nimbase.h",
|
||||||
|
"lib/*.nim -> lib",
|
||||||
|
|
||||||
|
"rod/*.nim -> rod",
|
||||||
|
"nim/*.pas -> nim",
|
||||||
|
"nim/*.txt -> nim",
|
||||||
|
|
||||||
|
"data/*.yml -> data",
|
||||||
|
"data/*.txt -> data",
|
||||||
|
|
||||||
|
"config/nimrod.cfg -> config/nimrod.cfg",
|
||||||
|
# documentation:
|
||||||
|
"doc/*.txt", # only include the text documentation; saves bandwidth!
|
||||||
|
# the installation program should generate the HTML
|
||||||
|
"readme.txt -> readme.txt",
|
||||||
|
"install.txt -> install.txt",
|
||||||
|
|
||||||
|
# library:
|
||||||
|
"lib/base/pcre_all.c -> lib/base/pcre_all.c",
|
||||||
|
"lib/base/pcre.nim -> lib/base/pcre.nim",
|
||||||
|
"lib/base/regexprs.nim -> lib/base/regexprs.nim",
|
||||||
|
#"lib/windows/winapi.nim -> lib/windows/winapi.nim"
|
||||||
|
# don't be too clever here; maybe useful on Linux
|
||||||
|
# for cross-compiling to Windows?
|
||||||
|
),
|
||||||
|
'windows': (
|
||||||
|
"bin/nim.exe -> bin/nim.exe",
|
||||||
|
"koch.exe -> koch.exe",
|
||||||
|
"lib/dlmalloc.h -> lib/dlmalloc.h",
|
||||||
|
"lib/dlmalloc.c -> lib/dlmalloc.c",
|
||||||
|
),
|
||||||
|
'linux': (
|
||||||
|
"lib/rod_gen/*.c -> build",
|
||||||
|
"rod/rod_gen/*.c -> build",
|
||||||
|
),
|
||||||
|
'macosx': (
|
||||||
|
"lib/rod_gen/*.c -> build",
|
||||||
|
"rod/rod_gen/*.c -> build",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getHost():
|
||||||
|
if os.name == 'nt': return "windows"
|
||||||
|
elif "linux" in sys.platform: return "linux"
|
||||||
|
elif "darwin" in sys.platform: return "macosx" # probably Mac OS X
|
||||||
|
# a heuristic that could work (most likely not :-):
|
||||||
|
else: return re.sub(r"[0-9]+$", r"", sys.platform).lower()
|
||||||
|
|
||||||
|
def iterInstallFiles(target=getHost()):
|
||||||
|
for section in ['common', target]:
|
||||||
|
for rule in distlist[section]:
|
||||||
|
splittedRule = re.split(r"\s*\-\>\s*", rule)
|
||||||
|
if len(splittedRule) == 2:
|
||||||
|
source, dest = splittedRule
|
||||||
|
if '*' in source:
|
||||||
|
for f in Glob(source):
|
||||||
|
yield (Path(f), Path(dest + '/' + os.path.split(f)[1]))
|
||||||
|
else:
|
||||||
|
yield (Path(source), Path(dest))
|
||||||
|
else:
|
||||||
|
for f in Glob(rule):
|
||||||
|
yield (Path(f), Path(f))
|
||||||
|
|
||||||
|
def cmd_dist(target=getHost()):
|
||||||
|
from zipfile import ZipFile
|
||||||
|
distfile = Path('dist/nimrod_%s_%s.zip' % (target, getVersion()))
|
||||||
|
Echo("creating: %s..." % distfile)
|
||||||
|
z = ZipFile(distfile, 'w', zipfile.ZIP_DEFLATED)
|
||||||
|
for source, dest in iterInstallFiles(target):
|
||||||
|
z.write(source, Path(dest))
|
||||||
|
z.close()
|
||||||
|
Echo("... done!")
|
||||||
|
|
||||||
|
# ------------------------------ windows installer ----------------------------
|
||||||
|
|
||||||
|
WIN_INSTALLER_TEMPLATE = (r"""
|
||||||
|
; File generated by koch.py
|
||||||
|
; Template by Andreas Rumpf
|
||||||
|
[Setup]
|
||||||
|
AppName=Nimrod Compiler
|
||||||
|
AppVerName=Nimrod Compiler $version
|
||||||
|
DefaultDirName={code:GiveMeAPath|nimrod}
|
||||||
|
DefaultGroupName=Nimrod
|
||||||
|
AllowNoIcons=yes
|
||||||
|
LicenseFile=nim\copying.txt
|
||||||
|
OutputDir=dist
|
||||||
|
OutputBaseFilename=install_nimrod_$version
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
PrivilegesRequired=none
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: english; MessagesFile: compiler:Default.isl
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
$files
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: {group}\Console for Nimrod; Filename: {cmd}
|
||||||
|
Name: {group}\Documentation; Filename: {app}\doc\index.html
|
||||||
|
Name: {group}\{cm:UninstallProgram,Nimrod Compiler}; Filename: {uninstallexe}
|
||||||
|
|
||||||
|
[UninstallDelete]
|
||||||
|
Type: files; Name: "{app}\config\nimrod.cfg"
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\bin\nimconf.exe"; Description: "Launch configuration"; """ +
|
||||||
|
"""Flags: postinstall nowait skipifsilent
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
function GiveMeAPath(const DefaultPathName: string): string;
|
||||||
|
begin
|
||||||
|
if IsAdminLoggedOn then Result := ExpandConstant('{pf}')
|
||||||
|
else Result := ExpandConstant('{userdocs}');
|
||||||
|
Result := Result + '\' + DefaultPathName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function setEnvCmd(const default: string): string;
|
||||||
|
var
|
||||||
|
op, app: string;
|
||||||
|
begin
|
||||||
|
app := ExpandConstant('{app}');
|
||||||
|
if IsAdminLoggedOn then op := '' else op := 'u';
|
||||||
|
result := '"' + app + '\bin\setenv.exe" -' + op + 'a PATH "%' + app + '\bin"'
|
||||||
|
end;
|
||||||
|
""")
|
||||||
|
|
||||||
|
def makeKochExe():
|
||||||
|
c = Changed("kochexe",
|
||||||
|
("docmacro.py kochmod.py koch.py " +
|
||||||
|
"misc/koch.ico").split(), EXPLAIN)
|
||||||
|
if c or force:
|
||||||
|
Exec("python " + Join(PYINSTALLER, "Makespec.py") +
|
||||||
|
" --onefile --ascii --icon=misc/koch.ico koch.py")
|
||||||
|
Exec("python " + Join(PYINSTALLER, "Build.py") + " koch.spec")
|
||||||
|
Remove("koch.spec")
|
||||||
|
Remove("warnkoch.txt")
|
||||||
|
RemoveDir("buildkoch")
|
||||||
|
c.success()
|
||||||
|
|
||||||
|
def cmd_wininstaller():
|
||||||
|
FILENAME = "install_nimrod.iss"
|
||||||
|
makeKochExe()
|
||||||
|
|
||||||
|
# generate an installer file
|
||||||
|
files = ""
|
||||||
|
for source, dest in iterInstallFiles("windows"):
|
||||||
|
files += ("Source: " + source + "; DestDir: {app}\\" +
|
||||||
|
os.path.split(dest)[0] + "; Flags: ignoreversion\n")
|
||||||
|
f = file(FILENAME, "w+")
|
||||||
|
f.write(Subs(WIN_INSTALLER_TEMPLATE, files=files, version=getVersion()))
|
||||||
|
f.close()
|
||||||
|
if RawExec(INNOSETUP + FILENAME) == 0:
|
||||||
|
# we cannot use ``Exec()`` here as this would
|
||||||
|
# mangle the ``/Q`` switch to ``\Q``
|
||||||
|
Remove(FILENAME)
|
||||||
|
|
||||||
|
# -------------------------- testing the compiler -----------------------------
|
||||||
|
|
||||||
|
# This part verifies Nimrod against the testcases.
|
||||||
|
# The testcases may contain the directives '#ERROR' or '#ERROR_IN'.
|
||||||
|
# '#ERROR' is used to indicate that the compiler should report
|
||||||
|
# an error in the marked line (the line that contains the '#ERROR'
|
||||||
|
# directive.)
|
||||||
|
# The format for '#ERROR_IN' is:
|
||||||
|
# #ERROR_IN filename linenumber
|
||||||
|
# One can omit the extension of the filename ('.nim' is then assumed).
|
||||||
|
# Tests which contain none of the two directives should compile. Thus they
|
||||||
|
# are executed after successful compilation and their output is verified
|
||||||
|
# against the results specified with the '#OUT' directive.
|
||||||
|
# (Tests which require user interaction are currently not possible.)
|
||||||
|
# Tests can have an #ERROR_MSG directive specifiying the error message
|
||||||
|
# Nimrod shall produce.
|
||||||
|
# The code here needs reworking or at least documentation, but I don't have
|
||||||
|
# the time and it has been debugged and optimized.
|
||||||
|
|
||||||
|
try:
|
||||||
|
import subprocess
|
||||||
|
HAS_SUBPROCESS = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_SUBPROCESS = False
|
||||||
|
|
||||||
|
def runProg(args, inp=None):
|
||||||
|
"""Executes the program + args given in args and
|
||||||
|
returns the output of the program as a string."""
|
||||||
|
if HAS_SUBPROCESS:
|
||||||
|
process = subprocess.Popen(args, bufsize=0, shell=True,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=inp,
|
||||||
|
universal_newlines=True)
|
||||||
|
standardOut, standardErr = process.communicate(inp)
|
||||||
|
process.wait() # be on the safe side
|
||||||
|
return standardOut
|
||||||
|
else:
|
||||||
|
if inp:
|
||||||
|
standardIn = file('buildin.tmp', 'w')
|
||||||
|
standardIn.write(inp)
|
||||||
|
standardIn.close()
|
||||||
|
b = " <buildin.tmp"
|
||||||
|
else:
|
||||||
|
b = ""
|
||||||
|
os.system(args + b + " >build.tmp")
|
||||||
|
result = file('build.tmp').read()
|
||||||
|
if not result: result = ""
|
||||||
|
return result
|
||||||
|
# system() is not optimal, but every Python version should have it
|
||||||
|
|
||||||
|
class Spec(object): pass # specification object
|
||||||
|
|
||||||
|
def parseTest(filename):
|
||||||
|
# spec is a table
|
||||||
|
reError = re.compile(r"#ERROR$")
|
||||||
|
reErrorIn = re.compile(r"#ERROR_IN\s*(\S*)\s*(\d*)")
|
||||||
|
reErrorMsg = re.compile(r"#ERROR_MSG\s*(.*)")
|
||||||
|
reOut = re.compile(r"#OUT\s*(.*)")
|
||||||
|
|
||||||
|
i = 0 # the line counter
|
||||||
|
spec = Spec()
|
||||||
|
spec.line = None # line number where compiler should throw an error
|
||||||
|
spec.file = None # file where compiler should throw an error
|
||||||
|
spec.err = False # true if the specification says there should be an error
|
||||||
|
spec.out = None # output that should be produced
|
||||||
|
|
||||||
|
for s in file(filename, 'rU'):
|
||||||
|
# we have to use this inefficient method for getting the current line
|
||||||
|
i += 1 # our line-counter
|
||||||
|
obj = reError.search(s)
|
||||||
|
if obj:
|
||||||
|
spec.line = i
|
||||||
|
spec.file = filename
|
||||||
|
spec.err = True
|
||||||
|
break
|
||||||
|
obj = reErrorIn.search(s)
|
||||||
|
if obj:
|
||||||
|
spec.file = obj.group(1)
|
||||||
|
spec.line = int(obj.group(2))
|
||||||
|
spec.err = True
|
||||||
|
if '.' not in specfile: specfile += ".nim"
|
||||||
|
break
|
||||||
|
obj = reOut.search(s)
|
||||||
|
if obj:
|
||||||
|
spec.out = obj.group(1)
|
||||||
|
break
|
||||||
|
obj = reErrorMsg.search(s)
|
||||||
|
if obj:
|
||||||
|
spec.out = obj.group(1)
|
||||||
|
spec.err = True
|
||||||
|
break
|
||||||
|
|
||||||
|
return spec
|
||||||
|
|
||||||
|
def doTest(filename, spec, options):
|
||||||
|
# call the compiler
|
||||||
|
# short filename for messages (better readability):
|
||||||
|
shortfile = os.path.split(filename)[1]
|
||||||
|
|
||||||
|
comp = Spec()
|
||||||
|
comp.line = 0
|
||||||
|
comp.file = None
|
||||||
|
comp.out = None
|
||||||
|
comp.err = False
|
||||||
|
# call the compiler and read the compiler message:
|
||||||
|
results = runProg("nim compile --hints:on " + options + " " + filename)
|
||||||
|
print results
|
||||||
|
# compiled regular expressions:
|
||||||
|
reLineInfoError = re.compile(r"^((.*)\((\d+), \d+\)\s*Error\:\s*(.*))",
|
||||||
|
re.MULTILINE)
|
||||||
|
reError = re.compile(r"^Error\:\s*(.*)", re.MULTILINE)
|
||||||
|
reSuccess = re.compile(r"^Hint\:\s*operation successful", re.MULTILINE)
|
||||||
|
obj = reLineInfoError.search(results)
|
||||||
|
if obj:
|
||||||
|
comp.err = True
|
||||||
|
comp.file = obj.group(2)
|
||||||
|
comp.line = int(obj.group(3))
|
||||||
|
comp.out = obj.group(1)
|
||||||
|
comp.puremsg = obj.group(4)
|
||||||
|
else:
|
||||||
|
comp.puremsg = ''
|
||||||
|
obj = reError.search(results)
|
||||||
|
if obj:
|
||||||
|
comp.err = True
|
||||||
|
comp.out = results
|
||||||
|
comp.puremsg = obj.group(1)
|
||||||
|
comp.line = 1
|
||||||
|
else:
|
||||||
|
obj = reSuccess.search(results)
|
||||||
|
if not obj: comp.err = True
|
||||||
|
|
||||||
|
if comp.err and not comp.out:
|
||||||
|
# the compiler did not say "[Error]" nor "Compilation sucessful"
|
||||||
|
Echo("[Tester] %s -- FAILED; COMPILER BROKEN" % shortfile)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (spec.err != comp.err
|
||||||
|
or (spec.line and (abs(spec.line - comp.line) > 1))
|
||||||
|
or (spec.file and (spec.file.lower() != comp.file.lower()))
|
||||||
|
or (spec.out and not (spec.out.strip() in comp.puremsg.strip()))):
|
||||||
|
if spec.out:
|
||||||
|
Echo("[Tester] %s -- FAILED\n"
|
||||||
|
"Compiler says: %s\n"
|
||||||
|
"But specification says: Error %s"
|
||||||
|
% (shortfile, comp.out, spec.out) )
|
||||||
|
elif spec.err:
|
||||||
|
if spec.file is None: spec.file = filename
|
||||||
|
if spec.line is None: spec.line = -1
|
||||||
|
Echo("[Tester] %s -- FAILED\n"
|
||||||
|
"Compiler says: %s\n"
|
||||||
|
"But specification says: Error in %s line %d"
|
||||||
|
% (shortfile, comp.out, spec.file, spec.line) )
|
||||||
|
else:
|
||||||
|
Echo("[Tester] %s -- FAILED\n"
|
||||||
|
"Compiler says: %s\n"
|
||||||
|
"But specification says: no error"
|
||||||
|
% (shortfile, comp.out) )
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if spec.err:
|
||||||
|
Echo("[Tester] " + shortfile + ' -- OK') # error correctly reported
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# run the compiled program and check if it works
|
||||||
|
fileNoExt = os.path.splitext(filename)[0]
|
||||||
|
if os.path.isfile(ExeExt(fileNoExt)):
|
||||||
|
if spec.out:
|
||||||
|
buf = runProg(fileNoExt)
|
||||||
|
if buf.strip() == spec.out.strip():
|
||||||
|
Echo("[Tester] " + shortfile + " -- compiled program OK")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
Echo("[Tester] " + shortfile + " -- compiled program FAILED")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
Echo("[Tester] " + shortfile + ' -- OK')
|
||||||
|
return True
|
||||||
|
# we have no output to validate against, but compilation succeeded,
|
||||||
|
# so it's okay
|
||||||
|
elif '--compile_only' in options:
|
||||||
|
Echo("[Tester] " + shortfile + ' -- OK')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
Echo("[Tester] " + shortfile + " -- FAILED\n"
|
||||||
|
"no compiled program found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def cmd_tests(options): # run the testsuite
|
||||||
|
"""runs the complete testsuite"""
|
||||||
|
#clean(True) # first clean before running the testsuite
|
||||||
|
total = 0
|
||||||
|
passed = 0
|
||||||
|
for filename in Glob("tests/t*.nim"):
|
||||||
|
spec = parseTest(filename)
|
||||||
|
res = doTest(filename, spec, options)
|
||||||
|
assert(res is not None)
|
||||||
|
if res: passed += 1
|
||||||
|
total += 1
|
||||||
|
break
|
||||||
|
Echo("[Tester] %d/%d tests passed\n" % (passed, total))
|
||||||
|
|
||||||
|
# --------------- install target ----------------------------------------------
|
||||||
|
|
||||||
|
CONFIG_TEMPLATE = r"""# Configuration file for the Nimrod Compiler.
|
||||||
|
# Generated by the koch.py script.
|
||||||
|
# (c) 2008 Andreas Rumpf
|
||||||
|
|
||||||
|
# Feel free to edit the default values as you need.
|
||||||
|
|
||||||
|
# You may set environment variables with
|
||||||
|
# @putenv "key" "val"
|
||||||
|
# Environment variables cannot be used in the options, however!
|
||||||
|
|
||||||
|
# Just call the compiler with several options:
|
||||||
|
cc = @if unix: %(cc)s @else: vcc @end
|
||||||
|
lib="$nimrod/lib"
|
||||||
|
path="$lib/base"
|
||||||
|
path="$lib/base/gtk"
|
||||||
|
path="$lib/base/cairo"
|
||||||
|
path="$lib/base/x11"
|
||||||
|
path="$lib/windows"
|
||||||
|
path="$lib/extra"
|
||||||
|
|
||||||
|
# additional defines:
|
||||||
|
#define=""
|
||||||
|
# additional options always passed to the compiler:
|
||||||
|
force_build
|
||||||
|
line_dir=off
|
||||||
|
|
||||||
|
hint[LineTooLong]=off
|
||||||
|
hint[XDeclaredButNotUsed]=off
|
||||||
|
|
||||||
|
@if unix:
|
||||||
|
passl= "-ldl"
|
||||||
|
path = "$lib/base/gtk"
|
||||||
|
@end
|
||||||
|
|
||||||
|
@if icc:
|
||||||
|
passl = "-cxxlib"
|
||||||
|
passc = "-cxxlib"
|
||||||
|
@end
|
||||||
|
|
||||||
|
# Configuration for the Borland C++ Compiler:
|
||||||
|
@if windows:
|
||||||
|
bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
|
||||||
|
@end
|
||||||
|
bcc.options.debug = ""
|
||||||
|
# turn off warnings about unreachable code and inline procs:
|
||||||
|
bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
|
||||||
|
bcc.options.speed = "-O2 -6"
|
||||||
|
bcc.options.size = "-O1 -6"
|
||||||
|
|
||||||
|
# Configuration for the Visual C/C++ compiler:
|
||||||
|
@if vcc:
|
||||||
|
@prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
|
||||||
|
@prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
|
||||||
|
@prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
|
||||||
|
@end
|
||||||
|
@if windows:
|
||||||
|
vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
|
||||||
|
@end
|
||||||
|
vcc.options.debug = "/GZ /ZI"
|
||||||
|
vcc.options.always = "/nologo"
|
||||||
|
vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
|
||||||
|
vcc.options.size = "/O1 /G7"
|
||||||
|
|
||||||
|
# Configuration for the Watcom C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
wcc.path = r"C:\eigenes\compiler\watcom\binnt"
|
||||||
|
@end
|
||||||
|
wcc.options.debug = "-d2"
|
||||||
|
wcc.options.always = "-6 -zw -w-"
|
||||||
|
wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
|
||||||
|
wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
|
||||||
|
|
||||||
|
# Configuration for the GNU C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
gcc.path = r"C:\eigenes\compiler\mingw\bin"
|
||||||
|
@end
|
||||||
|
gcc.options.debug = "-g"
|
||||||
|
@if macosx:
|
||||||
|
gcc.options.always = "-w -fasm-blocks"
|
||||||
|
@else:
|
||||||
|
gcc.options.always = "-w"
|
||||||
|
@end
|
||||||
|
gcc.options.speed = "-O3 -ffast-math"
|
||||||
|
gcc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
# Configuration for the Digital Mars C/C++ compiler:
|
||||||
|
@if windows:
|
||||||
|
dmc.path = r"C:\eigenes\compiler\d\dm\bin"
|
||||||
|
@end
|
||||||
|
dmc.options.debug = "-g"
|
||||||
|
dmc.options.always = "-Jm"
|
||||||
|
dmc.options.speed = "-ff -o -6"
|
||||||
|
dmc.options.size = "-ff -o -6"
|
||||||
|
|
||||||
|
# Configuration for the LCC compiler:
|
||||||
|
@if windows:
|
||||||
|
lcc.path = r"C:\eigenes\compiler\lcc\bin"
|
||||||
|
@end
|
||||||
|
lcc.options.debug = "-g5"
|
||||||
|
lcc.options.always = "-e1"
|
||||||
|
lcc.options.speed = "-O -p6"
|
||||||
|
lcc.options.size = "-O -p6"
|
||||||
|
|
||||||
|
# Configuration for the Tiny C Compiler:
|
||||||
|
@if windows:
|
||||||
|
tcc.path = r"C:\eigenes\compiler\tcc\bin"
|
||||||
|
@end
|
||||||
|
tcc.options.debug = "-b"
|
||||||
|
tcc.options.always = ""
|
||||||
|
tcc.options.speed = ""
|
||||||
|
tcc.options.size = ""
|
||||||
|
|
||||||
|
# Configuration for the Pelles C compiler:
|
||||||
|
@if windows:
|
||||||
|
pcc.path = r"C:\eigenes\compiler\pellesc\bin"
|
||||||
|
@end
|
||||||
|
pcc.options.debug = "-Zi"
|
||||||
|
pcc.options.always = "-Ze"
|
||||||
|
pcc.options.speed = "-Ox"
|
||||||
|
pcc.options.size = "-Os"
|
||||||
|
|
||||||
|
# Configuration for the LLVM GCC compiler:
|
||||||
|
@if windows:
|
||||||
|
llvm_gcc.path = r"c:\eignes\compiler\llvm-gcc\bin"
|
||||||
|
@end
|
||||||
|
llvm_gcc.options.debug = "-g"
|
||||||
|
llvm_gcc.options.always = "-w"
|
||||||
|
llvm_gcc.options.speed = "-O3 -ffast-math"
|
||||||
|
llvm_gcc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
@if windows:
|
||||||
|
icc.path = r"c:\eignes\compiler\icc\bin"
|
||||||
|
@end
|
||||||
|
icc.options.debug = "-g"
|
||||||
|
icc.options.always = "-w"
|
||||||
|
icc.options.speed = "-O3 -ffast-math"
|
||||||
|
icc.options.size = "-Os -ffast-math"
|
||||||
|
|
||||||
|
@write "used default config file"
|
||||||
|
"""
|
||||||
|
|
||||||
|
def writePlatdefC(nimrodpath):
|
||||||
|
import os
|
||||||
|
host = getHost()
|
||||||
|
if host == "windows": processor = "i386" # BUGFIX
|
||||||
|
else: processor = os.uname()[4]
|
||||||
|
if processor.lower() in ("i686", "i586", "i468", "i386"):
|
||||||
|
processor = "i386"
|
||||||
|
if "sparc" in processor.lower():
|
||||||
|
processor = "sparc"
|
||||||
|
f = file(os.path.join(nimrodpath, "build/platdef.c"), "w+")
|
||||||
|
f.write('/* Generated by koch.py */\n'
|
||||||
|
'#include "nimbase.h"\n'
|
||||||
|
'N_NIMCALL(char*, nimOS)(void) { return "%s"; }\n'
|
||||||
|
'N_NIMCALL(char*, nimCPU)(void) { return "%s"; }\n'
|
||||||
|
'\n' % (host, processor))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def detect(cmd, lookFor="version"):
|
||||||
|
pipe = os.popen4(cmd)[1]
|
||||||
|
result = None
|
||||||
|
for line in pipe:
|
||||||
|
if lookFor in line:
|
||||||
|
result = line[:-1]
|
||||||
|
break
|
||||||
|
pipe.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def lookForCC():
|
||||||
|
if "CC" in os.environ:
|
||||||
|
Echo("using $CC environment variable (%s)" % os.environ["CC"])
|
||||||
|
return os.environ["CC"]
|
||||||
|
d = detect("gcc -v")
|
||||||
|
if d:
|
||||||
|
Echo("'%s' detected" % d)
|
||||||
|
return "gcc"
|
||||||
|
Echo("GCC not found. Testing for generic CC...")
|
||||||
|
d = detect("cc -v")
|
||||||
|
if d:
|
||||||
|
Echo("'%s' detected" % d)
|
||||||
|
return "ucc"
|
||||||
|
Echo("...not found!")
|
||||||
|
Error("No C compiler could be found!")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def getNimrodPath():
|
||||||
|
if os.name == "posix":
|
||||||
|
# Does not work 100% reliably. It is the best solution though.
|
||||||
|
p = sys.argv[0].replace("./", "")
|
||||||
|
return os.path.split(os.path.join(os.getcwd(), p))[0]
|
||||||
|
else: # Windows
|
||||||
|
return os.path.split(sys.argv[0])[0]
|
||||||
|
|
||||||
|
def writeCfg(nimrodpath, ccSymbol=None):
|
||||||
|
if not ccSymbol:
|
||||||
|
ccSymbol = lookForCC()
|
||||||
|
configFile = os.path.join(nimrodpath, "config/nimrod.cfg")
|
||||||
|
script = CONFIG_TEMPLATE % {'cc': ccSymbol, 'nimrodpath': nimrodpath}
|
||||||
|
config = file(configFile)
|
||||||
|
if config:
|
||||||
|
if config.read().strip() != script.strip():
|
||||||
|
config.close()
|
||||||
|
Echo("Configuration file already exists and "
|
||||||
|
"seems to have been modified.\n"
|
||||||
|
"Do you want to override it? (y/n) ")
|
||||||
|
while True:
|
||||||
|
a = ask()
|
||||||
|
if a in ("y", "yes"):
|
||||||
|
f = file(configFile, "w+")
|
||||||
|
f.write(script)
|
||||||
|
f.close()
|
||||||
|
break
|
||||||
|
elif a in ("n", "no"):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
Echo("What do you mean? (y/n) ")
|
||||||
|
else:
|
||||||
|
config.close()
|
||||||
|
return ccSymbol
|
||||||
|
|
||||||
|
def cmd_install(args):
|
||||||
|
Echo("Nimrod should be in '%s'" % getNimrodPath())
|
||||||
|
# We know that the user has already unzipped this archive into the
|
||||||
|
# final directory. So we just create the config file and build Nimrod.
|
||||||
|
|
||||||
|
# write the configuration file, but check if one exists!
|
||||||
|
nimrodpath = getNimrodPath()
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(args, "", ["cc=", "ld="])
|
||||||
|
except getopt.GetoptError:
|
||||||
|
# print help information and exit:
|
||||||
|
Error("Command line contains errors")
|
||||||
|
ccSymbol = None
|
||||||
|
ldSymbol = None
|
||||||
|
for o, a in opts:
|
||||||
|
if o == "--cc": ccSymbol = a
|
||||||
|
elif o == "--ld": ldSymbol = a
|
||||||
|
|
||||||
|
ccSymbol = writeCfg(nimrodpath, ccSymbol)
|
||||||
|
if not ldSymbol:
|
||||||
|
ldSymbol = ccSymbol.split()[0] + " -ldl -o bin/nimrod "
|
||||||
|
|
||||||
|
writePlatdefC(nimrodpath)
|
||||||
|
|
||||||
|
# build Nimrod
|
||||||
|
link = "" # store the .o files in here for final linking step
|
||||||
|
for f in Glob("build/*.c"):
|
||||||
|
objfile = os.path.splitext(f)[0] + ".o"
|
||||||
|
link += " " + objfile
|
||||||
|
# compile only:
|
||||||
|
if Exec(ccSymbol + " " + CFLAGS + " -c -o " + objfile + " " + f) != 0:
|
||||||
|
Error("the C compiler did not like: " + f)
|
||||||
|
if link == "":
|
||||||
|
Error("could not find Nimrod's sources\n"
|
||||||
|
" (they should be in the build subdirectory)")
|
||||||
|
# now link the stuff together:
|
||||||
|
if Exec(ldSymbol + link) != 0:
|
||||||
|
Error("the linking step failed!")
|
||||||
|
# now we have a Nimrod executable :-)
|
||||||
|
|
||||||
|
nimrodpath = getNimrodPath()
|
||||||
|
writeScript(CONFIG_TEMPLATE % {'cc': ccSymbol, 'nimrodpath': nimrodpath},
|
||||||
|
os.path.join(nimrodpath, "config/nimrod.cfg"))
|
||||||
|
|
||||||
|
# remove the generated .o files as they take 1 MB:
|
||||||
|
for f in Glob("build/*.o"): Remove(f)
|
||||||
|
Echo("SUCCESS!")
|
||||||
|
|
||||||
|
def cmd_installer():
|
||||||
|
if os.name == "posix":
|
||||||
|
Echo("Nothing to do")
|
||||||
|
else: # Windows
|
||||||
|
cmd_wininstaller()
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------ configure ------------------------------------------------
|
||||||
|
|
||||||
|
def writeScript(script, filename):
|
||||||
|
if os.name != "posix": filename += ".bat"
|
||||||
|
f = file(filename, "w+")
|
||||||
|
f.write(script)
|
||||||
|
f.close()
|
||||||
|
# make the script executable:
|
||||||
|
if os.name == "posix":
|
||||||
|
os.chmod(filename, 493) # 0o755
|
||||||
|
|
||||||
|
def cmd_configure():
|
||||||
|
d = detect("fpc -h")
|
||||||
|
if d:
|
||||||
|
Echo("'%s' detected" % d)
|
||||||
|
else:
|
||||||
|
Warn("Free Pascal is not installed, bootstrapping may not work properly.")
|
||||||
|
writeCfg(getNimrodPath())
|
||||||
|
Echo("Configuration sucessful!")
|
||||||
|
|
||||||
|
# ------------------- main ----------------------------------------------------
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv[1:])
|
||||||
640
kochmod.py
Executable file
640
kochmod.py
Executable file
|
|
@ -0,0 +1,640 @@
|
||||||
|
# This is kochmod, a simple module for make-like functionality.
|
||||||
|
# For further documentation see koch.txt or koch.html.
|
||||||
|
# (c) 2007 Andreas Rumpf
|
||||||
|
|
||||||
|
VERSION = "1.0.3"
|
||||||
|
|
||||||
|
import os, os.path, inspect, re, shutil, glob, cPickle, zlib, string, \
|
||||||
|
getopt, sys
|
||||||
|
from types import *
|
||||||
|
|
||||||
|
def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
|
||||||
|
def Warn(msg): print "[Koch] *** WARNING: " + msg
|
||||||
|
def Echo(msg): print "[Koch] " + msg
|
||||||
|
def _Info(msg): print "[Koch] " + msg
|
||||||
|
|
||||||
|
_FINGERPRINTS_FILE = "koch.dat"
|
||||||
|
# in this file all the fingerprints are kept to allow recognizing when a file
|
||||||
|
# has changed. This works reliably, which cannot be said from just taking
|
||||||
|
# filetime-stamps.
|
||||||
|
|
||||||
|
# ---------------- C Compilers ------------------------------------------------
|
||||||
|
|
||||||
|
# We support the following C compilers:
|
||||||
|
C_Compilers = ["gcc", "lcc", "bcc", "dmc", "wcc", "tcc", "pcc", "ucc", "llvm"]
|
||||||
|
|
||||||
|
_CC_Info = [
|
||||||
|
dict(
|
||||||
|
name = "gcc",
|
||||||
|
objExt = "o",
|
||||||
|
optSpeed = " -O3 -ffast-math ",
|
||||||
|
optSize = " -Os -ffast-math ",
|
||||||
|
comp = "gcc -c $options $include -o $objfile $file",
|
||||||
|
buildGui = " -mwindows",
|
||||||
|
buildDll = " -mdll",
|
||||||
|
link = "gcc $options $buildgui $builddll -o $exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = "",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = "-fPIC"
|
||||||
|
), dict(
|
||||||
|
name = "lcc",
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " -O -p6 ",
|
||||||
|
optSize = " -O -p6 ",
|
||||||
|
comp = "lcc -e1 $options $include -Fo$objfile $file",
|
||||||
|
buildGui = " -subsystem windows",
|
||||||
|
buildDll = " -dll",
|
||||||
|
link = "lcclnk $options $buildgui $builddll -O $exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = " -g5 ",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "bcc",
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " -O2 -6 ",
|
||||||
|
optSize = " -O1 -6 ",
|
||||||
|
comp = "bcc32 -c -H- -q -RT- -a8 $options $include -o$objfile $file",
|
||||||
|
buildGui = " -tW",
|
||||||
|
buildDll = " -tWD",
|
||||||
|
link = "bcc32 $options $buildgui $builddll -e$exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = "",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "dmc",
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " -ff -o -6 ",
|
||||||
|
optSize = " -ff -o -6 ",
|
||||||
|
comp = "dmc -c -Jm $options $include -o$objfile $file",
|
||||||
|
buildGui = " -L/exet:nt/su:windows",
|
||||||
|
buildDll = " -WD",
|
||||||
|
link = "dmc $options $buildgui $builddll -o$exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = " -g ",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name", # XXX: dmc does not have -U ?
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "wcc",
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " -ox -on -6 -d0 -fp6 -zW ",
|
||||||
|
optSize = "",
|
||||||
|
comp = "wcl386 -c -6 -zw $options $include -fo=$objfile $file",
|
||||||
|
buildGui = " -bw",
|
||||||
|
buildDll = " -bd",
|
||||||
|
link = "wcl386 $options $buildgui $builddll -fe=$exefile $objfiles ",
|
||||||
|
includeCmd = " -i=",
|
||||||
|
debug = " -d2 ",
|
||||||
|
defineValue = " -d$name=$value",
|
||||||
|
define = " -d$name",
|
||||||
|
undef = " -u$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "vcc",
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " /Ogityb2 /G7 /arch:SSE2 ",
|
||||||
|
optSize = " /O1 /G7 ",
|
||||||
|
comp = "cl /c $options $include /Fo$objfile $file",
|
||||||
|
buildGui = " /link /SUBSYSTEM:WINDOWS ",
|
||||||
|
buildDll = " /LD",
|
||||||
|
link = "cl $options $builddll /Fe$exefile $objfiles $buildgui",
|
||||||
|
includeCmd = " /I",
|
||||||
|
debug = " /GZ /Zi ",
|
||||||
|
defineValue = " /D$name=$value",
|
||||||
|
define = " /D$name",
|
||||||
|
undef = " /U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "tcc",
|
||||||
|
objExt = "o",
|
||||||
|
optSpeed = "", # Tiny C has no optimizer
|
||||||
|
optSize = "",
|
||||||
|
comp = "tcc -c $options $include -o $objfile $file",
|
||||||
|
buildGui = "UNAVAILABLE!",
|
||||||
|
buildDll = " -shared",
|
||||||
|
link = "tcc -o $exefile $options $buildgui $builddll $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = " -b ",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "pcc", # Pelles C
|
||||||
|
objExt = "obj",
|
||||||
|
optSpeed = " -Ox ",
|
||||||
|
optSize = " -Os ",
|
||||||
|
comp = "cc -c $options $include -Fo$objfile $file",
|
||||||
|
buildGui = " -SUBSYSTEM:WINDOWS",
|
||||||
|
buildDll = " -DLL",
|
||||||
|
link = "cc $options $buildgui $builddll -OUT:$exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = " -Zi ",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "ucc",
|
||||||
|
objExt = "o",
|
||||||
|
optSpeed = " -O3 ",
|
||||||
|
optSize = " -O1 ",
|
||||||
|
comp = "cc -c $options $include -o $objfile $file",
|
||||||
|
buildGui = "",
|
||||||
|
buildDll = " -shared ",
|
||||||
|
link = "cc -o $exefile $options $buildgui $builddll $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = "",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = ""
|
||||||
|
), dict(
|
||||||
|
name = "llvm_gcc", # its options are the same as GCC's
|
||||||
|
objExt = "o",
|
||||||
|
optSpeed = " -O3 -ffast-math ",
|
||||||
|
optSize = " -Os -ffast-math ",
|
||||||
|
comp = "llvm-gcc -c $options $include -o $objfile $file",
|
||||||
|
buildGui = " -mwindows",
|
||||||
|
buildDll = " -mdll",
|
||||||
|
link = "llvm-gcc $options $buildgui $builddll -o $exefile $objfiles",
|
||||||
|
includeCmd = " -I",
|
||||||
|
debug = "",
|
||||||
|
defineValue = " -D$name=$value",
|
||||||
|
define = " -D$name",
|
||||||
|
undef = " -U$name",
|
||||||
|
pic = "-fPIC"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# --------------- little helpers ---------------------------------------------
|
||||||
|
|
||||||
|
def Subs(frmt, **substitution):
|
||||||
|
if isinstance(frmt, basestring):
|
||||||
|
return string.Template(frmt).substitute(substitution)
|
||||||
|
else:
|
||||||
|
return tuple([string.Template(x).substitute(substitution) for x in frmt])
|
||||||
|
|
||||||
|
_baseDir = os.getcwd()
|
||||||
|
BaseDir = _baseDir
|
||||||
|
|
||||||
|
def Path(a):
|
||||||
|
# Gets a UNIX like path and converts it to a path on this platform.
|
||||||
|
# With UNIX like, I mean: slashes, not backslashes, only relative
|
||||||
|
# paths ('../etc' can be used)
|
||||||
|
result = a
|
||||||
|
if os.sep != "/": result = result.replace("/", os.sep)
|
||||||
|
if os.pardir != "..": result = result.replace("..", os.pardir)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def Join(*args):
|
||||||
|
result = ""
|
||||||
|
for a in args[:-1]:
|
||||||
|
result += a
|
||||||
|
if result[-1] != "/":
|
||||||
|
result += "/"
|
||||||
|
result += args[-1]
|
||||||
|
return result.replace("//", "/")
|
||||||
|
|
||||||
|
def Exec(command):
|
||||||
|
c = Path(command)
|
||||||
|
Echo(c)
|
||||||
|
result = os.system(c)
|
||||||
|
if result != 0: Error("execution of an external program failed")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def TryExec(command):
|
||||||
|
c = Path(command)
|
||||||
|
Echo(c)
|
||||||
|
result = os.system(c)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def RawExec(command):
|
||||||
|
Echo(command)
|
||||||
|
result = os.system(command)
|
||||||
|
if result != 0: Error("execution of an external program failed")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def Move(src, dest):
|
||||||
|
s = Path(src)
|
||||||
|
d = Path(dest)
|
||||||
|
try:
|
||||||
|
shutil.move(s, d)
|
||||||
|
except IOError, OSError:
|
||||||
|
Warn("could not move %s to %s" % (s, d))
|
||||||
|
|
||||||
|
def Copy(src, dest):
|
||||||
|
s = Path(src)
|
||||||
|
d = Path(dest)
|
||||||
|
try:
|
||||||
|
shutil.copyfile(s, d)
|
||||||
|
except IOError, OSError:
|
||||||
|
Warn("could not copy %s to %s" % (s, d))
|
||||||
|
|
||||||
|
def Remove(f):
|
||||||
|
try:
|
||||||
|
os.remove(Path(f))
|
||||||
|
except OSError:
|
||||||
|
Warn("could not remove: %s" % f)
|
||||||
|
|
||||||
|
def RemoveDir(f):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(Path(f))
|
||||||
|
except OSError:
|
||||||
|
Warn("could not remove: %s" % f)
|
||||||
|
|
||||||
|
def Exists(f): return os.path.exists(Path(f))
|
||||||
|
|
||||||
|
def Chdir(dest):
|
||||||
|
d = Path(dest)
|
||||||
|
try:
|
||||||
|
os.chdir(d)
|
||||||
|
except OSError:
|
||||||
|
Warn("could not switch to directory: " + d)
|
||||||
|
|
||||||
|
def Mkdir(dest):
|
||||||
|
d = Path(dest)
|
||||||
|
try:
|
||||||
|
os.mkdir(d)
|
||||||
|
except OSError:
|
||||||
|
Warn("could not create directory: " + d)
|
||||||
|
|
||||||
|
def Glob(pattern): # needed because glob.glob() is buggy on Windows 95:
|
||||||
|
# things like tests/t*.mor won't work
|
||||||
|
global _baseDir
|
||||||
|
(head, tail) = os.path.split(Path(pattern))
|
||||||
|
try:
|
||||||
|
os.chdir(os.path.join(_baseDir, head))
|
||||||
|
result = []
|
||||||
|
for f in glob.glob(tail):
|
||||||
|
result.append(os.path.join(head, f))
|
||||||
|
except OSError:
|
||||||
|
result = []
|
||||||
|
finally:
|
||||||
|
os.chdir(_baseDir)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def FilenameNoExt(f):
|
||||||
|
return os.path.splitext(os.path.basename(f))[0]
|
||||||
|
|
||||||
|
def _Ext(trunc, posixFormat, winFormat):
|
||||||
|
(head, tail) = os.path.split(Path(trunc))
|
||||||
|
if os.name == "posix": frmt = posixFormat
|
||||||
|
else: frmt = winFormat
|
||||||
|
return os.path.join(head, Subs(frmt, trunc=tail))
|
||||||
|
|
||||||
|
def DynExt(trunc):
|
||||||
|
"""Makes a dynamic library out of a trunc. This means it either
|
||||||
|
does '${trunc}.dll' or 'lib${trunc}.so'.
|
||||||
|
"""
|
||||||
|
return _Ext(trunc, 'lib${trunc}.so', '${trunc}.dll')
|
||||||
|
|
||||||
|
def LibExt(trunc):
|
||||||
|
"""Makes a static library out of a trunc. This means it either
|
||||||
|
does '${trunc}.lib' or '${trunc}.a'.
|
||||||
|
"""
|
||||||
|
return _Ext(trunc, '${trunc}.a', '${trunc}.lib')
|
||||||
|
|
||||||
|
def ScriptExt(trunc):
|
||||||
|
"""Makes a script out of a trunc. This means it either
|
||||||
|
does '${trunc}.bat' or '${trunc}.sh'.
|
||||||
|
"""
|
||||||
|
return _Ext(trunc, '${trunc}.sh', '${trunc}.bat')
|
||||||
|
|
||||||
|
def ExeExt(trunc):
|
||||||
|
"""Makes an executable out of a trunc. This means it either
|
||||||
|
does '${trunc}.exe' or '${trunc}'.
|
||||||
|
"""
|
||||||
|
return _Ext(trunc, '${trunc}', '${trunc}.exe')
|
||||||
|
|
||||||
|
def MakeExecutable(file):
|
||||||
|
os.chmod(file, 493)
|
||||||
|
|
||||||
|
# ----------------- Dependency Analyser Core ---------------------------------
|
||||||
|
# We simply store the rules in a list until building the things. Checking is
|
||||||
|
# also delayed.
|
||||||
|
_rules = {}
|
||||||
|
_importantTargets = [] # used for command line switches
|
||||||
|
_commands = {} # other commands
|
||||||
|
# a command is a tuple: (name, description, function, number of arguments)
|
||||||
|
|
||||||
|
def Command(name, desc, func, args=0):
|
||||||
|
"""if args == -1, a variable number of arguments is given to the ``func``
|
||||||
|
as a list"""
|
||||||
|
_commands[name] = (desc, func, args)
|
||||||
|
|
||||||
|
def _applyPath(x):
|
||||||
|
if type(x) == ListType:
|
||||||
|
return map(Path, x)
|
||||||
|
else:
|
||||||
|
return Path(x)
|
||||||
|
|
||||||
|
def Rule(name = None, desc = "", prereqs = [], cmds = None, outputfile = None,
|
||||||
|
modifies = []):
|
||||||
|
"""Defines a rule. Name must be a single word, not a file!"""
|
||||||
|
if not name:
|
||||||
|
t = "#" + str(len(_rules.keys()))
|
||||||
|
else:
|
||||||
|
t = name
|
||||||
|
if t in _rules: Error("target '%s' already exists!" % t)
|
||||||
|
_rules[t] = (_applyPath(prereqs), cmds, outputfile, _applyPath(modifies))
|
||||||
|
if desc:
|
||||||
|
_importantTargets.append((t, desc))
|
||||||
|
|
||||||
|
|
||||||
|
class Changed(object):
|
||||||
|
""" Returns a Changed object. This object evals to true if one of the
|
||||||
|
given files has changed, false otherwise in a boolean context. You have
|
||||||
|
to call the object's success() method if the building has been a success.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
c = Changed("unique_name", "file1.pas file2.pas file3.pas")
|
||||||
|
if c:
|
||||||
|
Exec("fpc file1.pas")
|
||||||
|
# Exec raises an exception if it fails, thus if we get to here, it was
|
||||||
|
# a success:
|
||||||
|
c.success()
|
||||||
|
"""
|
||||||
|
def __init__(self, id, files, explain=False,
|
||||||
|
fingerprintsfile=_FINGERPRINTS_FILE):
|
||||||
|
# load the fingerprints file:
|
||||||
|
# fingerprints is a dict[target, files] where files is a dict[filename, hash]
|
||||||
|
self.fingers = {} # default value
|
||||||
|
if Exists(fingerprintsfile):
|
||||||
|
try:
|
||||||
|
self.fingers = cPickle.load(file(fingerprintsfile))
|
||||||
|
except OSError:
|
||||||
|
Error("Cannot read from " + fingerprintsfile)
|
||||||
|
self.filename = fingerprintsfile
|
||||||
|
self.id = id
|
||||||
|
self.files = files
|
||||||
|
self._hashStr = zlib.adler32 # our hash function
|
||||||
|
self.explain = explain
|
||||||
|
|
||||||
|
def _hashFile(self, f):
|
||||||
|
x = file(f)
|
||||||
|
result = self._hashStr(x.read())
|
||||||
|
x.close() # for other Python implementations
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
if type(self.files) == type(""):
|
||||||
|
self.files = self.files.split()
|
||||||
|
result = False
|
||||||
|
target = self.id
|
||||||
|
if not (target in self.fingers):
|
||||||
|
self.fingers[target] = {}
|
||||||
|
if self.explain: _Info("no entries for target '%s'" % target)
|
||||||
|
result = True
|
||||||
|
for d in self.files:
|
||||||
|
if Exists(d):
|
||||||
|
n = self._hashFile(d)
|
||||||
|
if d not in self.fingers[target] or n != self.fingers[target][d]:
|
||||||
|
result = True
|
||||||
|
if self.explain: _Info("'%s' modified since last build" % d)
|
||||||
|
self.fingers[target][d] = n
|
||||||
|
else:
|
||||||
|
Warn("'%s' does not exist!" % d)
|
||||||
|
result = True
|
||||||
|
return result
|
||||||
|
|
||||||
|
def update(self, filename):
|
||||||
|
self.fingers[self.id][filename] = self._hashFile(filename)
|
||||||
|
|
||||||
|
def success(self):
|
||||||
|
cPickle.dump(self.fingers, file(self.filename, "w+"))
|
||||||
|
|
||||||
|
|
||||||
|
class _Koch(object):
|
||||||
|
def _loadFingerprints(self, filename):
|
||||||
|
# fingerprints is a dict[target, files] where files is a dict[filename, hash]
|
||||||
|
if Exists(filename):
|
||||||
|
try:
|
||||||
|
self.fingers = cPickle.load(file(filename))
|
||||||
|
except OSError:
|
||||||
|
Error("Cannot read from " + filename)
|
||||||
|
else:
|
||||||
|
self.fingers = {} # we have no fingerprints :-(
|
||||||
|
|
||||||
|
def _saveFingerprints(self, filename):
|
||||||
|
cPickle.dump(self.fingers, file(filename, "w+"))
|
||||||
|
|
||||||
|
def __init__(self, options):
|
||||||
|
self._loadFingerprints(_FINGERPRINTS_FILE)
|
||||||
|
self.newfingers = {}
|
||||||
|
self.rules = _rules
|
||||||
|
self._hashStr = zlib.adler32 # our hash function
|
||||||
|
self.options = options
|
||||||
|
|
||||||
|
def _doRebuild(self, cmd):
|
||||||
|
if cmd is None: return 0
|
||||||
|
if type(cmd) is StringType:
|
||||||
|
if cmd:
|
||||||
|
c = Path(cmd)
|
||||||
|
_Info(c)
|
||||||
|
return os.system(c)
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
elif type(cmd) is FunctionType:
|
||||||
|
return cmd()
|
||||||
|
elif type(cmd) is ListType:
|
||||||
|
for c in cmd:
|
||||||
|
res = self._doRebuild(c)
|
||||||
|
if res != 0: break
|
||||||
|
return res
|
||||||
|
else:
|
||||||
|
Error("invalid rule: command must be a string or a function")
|
||||||
|
|
||||||
|
def _hashFile(self, f):
|
||||||
|
x = file(f)
|
||||||
|
result = self._hashStr(x.read())
|
||||||
|
x.close() # for other Python implementations
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _getDeps(self, target):
|
||||||
|
depslist = self.rules[target][0]
|
||||||
|
if type(depslist) is StringType:
|
||||||
|
result = depslist.split()
|
||||||
|
elif type(depslist) is FunctionType:
|
||||||
|
result = depslist()
|
||||||
|
elif type(depslist) is ListType:
|
||||||
|
result = []
|
||||||
|
for d in depslist:
|
||||||
|
if type(d) is StringType:
|
||||||
|
result.append(d)
|
||||||
|
elif type(d) is FunctionType:
|
||||||
|
result.append(d())
|
||||||
|
else:
|
||||||
|
Error("invalid rule: prereqs must be a string, list, or a function")
|
||||||
|
for i in range(0, len(result)):
|
||||||
|
result[i] = Path(result[i])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _hasChanged(self, target, d):
|
||||||
|
if not (target in self.newfingers):
|
||||||
|
self.newfingers[target] = {}
|
||||||
|
if Exists(d):
|
||||||
|
n = self._hashFile(d)
|
||||||
|
self.newfingers[target][d] = n
|
||||||
|
if not (target in self.fingers): return True
|
||||||
|
if not (d in self.fingers[target]): return True
|
||||||
|
return n != self.fingers[target][d]
|
||||||
|
else:
|
||||||
|
Warn("'%s' does not exist!" % d)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _makeAux(self, target, callstack={}):
|
||||||
|
# returns "uptodate", "updated", "failed"
|
||||||
|
UPTODATE = 1
|
||||||
|
UPDATED = 2
|
||||||
|
FAILED = 3
|
||||||
|
|
||||||
|
if target in callstack: return callstack[target]
|
||||||
|
|
||||||
|
def explain(msg):
|
||||||
|
if 'explain' in self.options: _Info(msg)
|
||||||
|
|
||||||
|
if not (target in self.rules): return UPTODATE # target is up to date
|
||||||
|
callstack[target] = UPTODATE # assume uptodate until proven otherwise
|
||||||
|
result = UPTODATE
|
||||||
|
|
||||||
|
# retrieve the dependencies:
|
||||||
|
deps = self._getDeps(target)
|
||||||
|
for d in deps:
|
||||||
|
if d[0] == '#':
|
||||||
|
t = d[1:]
|
||||||
|
if not (t in self.rules):
|
||||||
|
Error("reference to unknown target '%s'" % t)
|
||||||
|
# it is a target!
|
||||||
|
#callstack[t] = # XXX: prevend endless recursion!
|
||||||
|
res = self._makeAux(t, callstack)
|
||||||
|
result = max(result, res)
|
||||||
|
if res == UPDATED:
|
||||||
|
explain("will build '%s' because '%s' modified since last build" %
|
||||||
|
(target, d))
|
||||||
|
elif res == FAILED:
|
||||||
|
explain("cannot build '%s' because '%s' failed" %
|
||||||
|
(target, d))
|
||||||
|
elif self._hasChanged(target, d):
|
||||||
|
explain("will build '%s' because '%s' modified since last build" %
|
||||||
|
(target, d))
|
||||||
|
result = max(result, UPDATED)
|
||||||
|
if self.rules[target][2]: # check if output file exists:
|
||||||
|
if not Exists(self.rules[target][2]):
|
||||||
|
explain("will build '%s' because output file '%s' does not exist" %
|
||||||
|
(target, self.rules[target][2]))
|
||||||
|
result = max(result, UPDATED)
|
||||||
|
|
||||||
|
if result == UPTODATE and 'force' in self.options:
|
||||||
|
explain("will build '%s' because forced" % target)
|
||||||
|
result = max(result, UPDATED)
|
||||||
|
|
||||||
|
if result == UPDATED:
|
||||||
|
_Info("building target '%s'" % target)
|
||||||
|
buildRes = self._doRebuild(self.rules[target][1])
|
||||||
|
if buildRes is None:
|
||||||
|
Error("builder for target '%s' did not return an int" % target)
|
||||||
|
result = FAILED
|
||||||
|
elif buildRes != 0:
|
||||||
|
result = FAILED
|
||||||
|
elif result == UPTODATE:
|
||||||
|
_Info("'%s' is up to date" % target)
|
||||||
|
callstack[target] = result
|
||||||
|
if result == UPDATED: # building was successful, so update fingerprints:
|
||||||
|
if not (target in self.newfingers):
|
||||||
|
# for phony targets this check is needed
|
||||||
|
self.newfingers[target] = {}
|
||||||
|
for m in self.rules[target][3]: # look for changed files
|
||||||
|
self._hasChanged(target, m) # call for its side-effects
|
||||||
|
self.fingers[target] = self.newfingers[target]
|
||||||
|
return result
|
||||||
|
|
||||||
|
def make(self, target):
|
||||||
|
self._makeAux(target)
|
||||||
|
self._saveFingerprints(_FINGERPRINTS_FILE)
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def SplitArg(s):
|
||||||
|
if ':' in s: c = ':'
|
||||||
|
elif '=' in s: c = '='
|
||||||
|
else: return (s, '')
|
||||||
|
i = s.find(c)
|
||||||
|
return (s[:i], s[i+1:])
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _writeUsage():
|
||||||
|
print("Usage: koch.py [options] command/target [command/target...]\n"
|
||||||
|
"Options:\n"
|
||||||
|
" --force, -b, -f forces rebuilding\n"
|
||||||
|
" --help, -h shows this help\n"
|
||||||
|
" --explain, -e explain why a target is built\n"
|
||||||
|
"Available targets:")
|
||||||
|
for t in _importantTargets:
|
||||||
|
print(" " + t[0] + " " * (23-len(t[0])) + t[1])
|
||||||
|
if len(_commands) > 0:
|
||||||
|
print("Available commands:")
|
||||||
|
for k, v in _commands.iteritems():
|
||||||
|
print(" " + k + " " * (23-len(k)) + v[0])
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def Koch(defaultTarget):
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
|
options = {}
|
||||||
|
i = 0
|
||||||
|
# process general options:
|
||||||
|
while i < len(argv):
|
||||||
|
if argv[i][0] == '-':
|
||||||
|
if argv[i] in ("-h", "--help"): _writeUsage()
|
||||||
|
elif argv[i] in ("-b", "-B", "--force", "-f"): options['force'] = True
|
||||||
|
elif argv[i] in ("--explain", "-e"): options['explain'] = True
|
||||||
|
else: Error("invalid option: '%s'" % argv[i])
|
||||||
|
else: break # BUGFIX
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
k = _Koch(options)
|
||||||
|
|
||||||
|
# process commands:
|
||||||
|
i = 0
|
||||||
|
while i < len(argv):
|
||||||
|
if argv[i][0] != '-': # process target/command
|
||||||
|
if argv[i] in _rules:
|
||||||
|
k.make(argv[i])
|
||||||
|
elif argv[i] in _commands:
|
||||||
|
cmd = argv[i]
|
||||||
|
n = _commands[cmd][2]
|
||||||
|
args = []
|
||||||
|
if n < 0: upperBound = len(argv)-1
|
||||||
|
else: upperBound = i+n
|
||||||
|
while i+1 <= upperBound:
|
||||||
|
if i+1 >= len(argv):
|
||||||
|
Error("command '%s' expects %d arguments" % (cmd, n))
|
||||||
|
args.append(argv[i+1])
|
||||||
|
i += 1
|
||||||
|
if n < 0: _commands[cmd][1](args)
|
||||||
|
else: _commands[cmd][1](*args)
|
||||||
|
else:
|
||||||
|
Error("Invalid target/command: " + argv[i])
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
if len(argv) == 0:
|
||||||
|
k.make(defaultTarget)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
Error("You should execute the file 'koch.py' or consult\n"
|
||||||
|
"the documentation to see how to build this software.")
|
||||||
|
|
||||||
|
|
||||||
39
lib/amd64.asm.in
Executable file
39
lib/amd64.asm.in
Executable file
|
|
@ -0,0 +1,39 @@
|
||||||
|
; This contains the CPU-dependant variants of some routines.
|
||||||
|
; (C) 2005 Andreas Rumpf
|
||||||
|
; This code was inspired by the Freepascal compiler's sources
|
||||||
|
; All routines here have the _cdecl calling convention because
|
||||||
|
; that is the only convention any C compiler supports.
|
||||||
|
|
||||||
|
\python{
|
||||||
|
# as usual I use my own preprocessor :-)
|
||||||
|
import os
|
||||||
|
|
||||||
|
def c(name):
|
||||||
|
if os.name == 'posix':
|
||||||
|
return name
|
||||||
|
else:
|
||||||
|
return "_" + name
|
||||||
|
|
||||||
|
def arg:
|
||||||
|
if os.name == 'posix':
|
||||||
|
return 'rdi'
|
||||||
|
else:
|
||||||
|
return 'rcx' # on win64 uses its own calling convention; this sucks!
|
||||||
|
}
|
||||||
|
|
||||||
|
segment code
|
||||||
|
|
||||||
|
global \c{cpu_inc_locked}
|
||||||
|
global \c{cpu_dec_locked}
|
||||||
|
|
||||||
|
\c{cpu_dec_locked}:
|
||||||
|
lock
|
||||||
|
dec [\arg]
|
||||||
|
setz al
|
||||||
|
ret
|
||||||
|
|
||||||
|
\c{cpu_inc_locked}:
|
||||||
|
lock
|
||||||
|
inc [\arg]
|
||||||
|
setz al
|
||||||
|
ret
|
||||||
84
lib/ansi_c.nim
Executable file
84
lib/ansi_c.nim
Executable file
|
|
@ -0,0 +1,84 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This include file contains headers of Ansi C procs
|
||||||
|
# and definitions of Ansi C types in Nimrod syntax
|
||||||
|
# All symbols are prefixed with 'c_' to avoid ambiguities
|
||||||
|
|
||||||
|
proc c_strcmp(a, b: CString): cint {.nodecl, importc: "strcmp".}
|
||||||
|
proc c_memcmp(a, b: CString, size: cint): cint {.nodecl, importc: "memcmp".}
|
||||||
|
proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
|
||||||
|
proc c_strlen(a: CString): cint {.nodecl, importc: "strlen".}
|
||||||
|
|
||||||
|
type
|
||||||
|
C_TextFile {.importc: "FILE", nodecl.} = record # empty record for
|
||||||
|
# data hiding
|
||||||
|
C_BinaryFile {.importc: "FILE", nodecl.} = record
|
||||||
|
C_TextFileStar = ptr CTextFile
|
||||||
|
C_BinaryFileStar = ptr CBinaryFile
|
||||||
|
|
||||||
|
C_JmpBuf {.importc: "jmp_buf".} = array[0..31, int]
|
||||||
|
|
||||||
|
var
|
||||||
|
c_stdin {.importc: "stdin", noDecl.}: C_TextFileStar
|
||||||
|
c_stdout {.importc: "stdout", noDecl.}: C_TextFileStar
|
||||||
|
c_stderr {.importc: "stderr", noDecl.}: C_TextFileStar
|
||||||
|
|
||||||
|
var # constants faked as variables:
|
||||||
|
SIGINT {.importc: "SIGINT", nodecl.}: cint
|
||||||
|
SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
|
||||||
|
SIGABRT {.importc: "SIGABRT", nodecl.}: cint
|
||||||
|
SIGFPE {.importc: "SIGFPE", nodecl.}: cint
|
||||||
|
SIGILL {.importc: "SIGILL", nodecl.}: cint
|
||||||
|
|
||||||
|
when defined(macosx):
|
||||||
|
var
|
||||||
|
SIGBUS {.importc: "SIGBUS", nodecl.}: cint
|
||||||
|
# hopefully this does not lead to new bugs
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
SIGBUS {.importc: "SIGSEGV", nodecl.}: cint
|
||||||
|
# only Mac OS X has this shit
|
||||||
|
|
||||||
|
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.nodecl, importc: "longjmp".}
|
||||||
|
proc c_setjmp(jmpb: var C_JmpBuf) {.nodecl, importc: "setjmp".}
|
||||||
|
|
||||||
|
proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
|
||||||
|
importc: "signal", header: "<signal.h>".}
|
||||||
|
proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
|
||||||
|
|
||||||
|
proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", noDecl.}
|
||||||
|
proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring {.
|
||||||
|
importc: "fgets", noDecl.}
|
||||||
|
proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", nodecl.}
|
||||||
|
proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", nodecl.}
|
||||||
|
proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc", nodecl.}
|
||||||
|
proc c_fprintf(f: C_TextFileStar, frmt: CString) {.
|
||||||
|
importc: "fprintf", nodecl, varargs.}
|
||||||
|
|
||||||
|
proc c_fopen(filename, mode: cstring): C_TextFileStar {.
|
||||||
|
importc: "fopen", nodecl.}
|
||||||
|
proc c_fclose(f: C_TextFileStar) {.importc: "fclose", nodecl.}
|
||||||
|
|
||||||
|
proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.}
|
||||||
|
# we use it only in a way that cannot lead to security issues
|
||||||
|
|
||||||
|
proc c_fread(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
|
||||||
|
importc: "fread", noDecl.}
|
||||||
|
proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
|
||||||
|
importc: "fseek", noDecl.}
|
||||||
|
|
||||||
|
proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
|
||||||
|
importc: "fwrite", noDecl.}
|
||||||
|
|
||||||
|
proc c_exit(errorcode: cint) {.importc: "exit", nodecl.}
|
||||||
|
proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.}
|
||||||
|
proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.}
|
||||||
|
proc c_abort() {.importc: "abort", nodecl.}
|
||||||
|
proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.}
|
||||||
347
lib/arithm.nim
Executable file
347
lib/arithm.nim
Executable file
|
|
@ -0,0 +1,347 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# simple integer arithmetic with overflow checking
|
||||||
|
|
||||||
|
proc raiseOverflow {.exportc: "raiseOverflow".} =
|
||||||
|
# a single proc to reduce code size to a minimum
|
||||||
|
raise newException(EOverflow, "over- or underflow")
|
||||||
|
|
||||||
|
proc raiseDivByZero {.exportc: "raiseDivByZero".} =
|
||||||
|
raise newException(EDivByZero, "divison by zero")
|
||||||
|
|
||||||
|
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
||||||
|
result = a + b
|
||||||
|
if (result xor a) >= int64(0) or (result xor b) >= int64(0):
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
||||||
|
result = a - b
|
||||||
|
if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc negInt64(a: int64): int64 {.compilerProc, inline.} =
|
||||||
|
if a != low(int64): return -a
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc absInt64(a: int64): int64 {.compilerProc, inline.} =
|
||||||
|
if a != low(int64):
|
||||||
|
if a >= 0: return a
|
||||||
|
else: return -a
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc divInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
||||||
|
if b == int64(0):
|
||||||
|
raiseDivByZero()
|
||||||
|
if a == low(int64) and b == int64(-1):
|
||||||
|
raiseOverflow()
|
||||||
|
return a div b
|
||||||
|
|
||||||
|
proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
|
||||||
|
if b == int64(0):
|
||||||
|
raiseDivByZero()
|
||||||
|
return a mod b
|
||||||
|
|
||||||
|
#
|
||||||
|
# This code has been inspired by Python's source code.
|
||||||
|
# The native int product x*y is either exactly right or *way* off, being
|
||||||
|
# just the last n bits of the true product, where n is the number of bits
|
||||||
|
# in an int (the delivered product is the true product plus i*2**n for
|
||||||
|
# some integer i).
|
||||||
|
#
|
||||||
|
# The native float64 product x*y is subject to three
|
||||||
|
# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
|
||||||
|
# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
|
||||||
|
# But, unlike the native int product, it's not in *range* trouble: even
|
||||||
|
# if sizeof(int)==32 (256-bit ints), the product easily fits in the
|
||||||
|
# dynamic range of a float64. So the leading 50 (or so) bits of the float64
|
||||||
|
# product are correct.
|
||||||
|
#
|
||||||
|
# We check these two ways against each other, and declare victory if they're
|
||||||
|
# approximately the same. Else, because the native int product is the only
|
||||||
|
# one that can lose catastrophic amounts of information, it's the native int
|
||||||
|
# product that must have overflowed.
|
||||||
|
#
|
||||||
|
proc mulInt64(a, b: int64): int64 {.compilerproc.} =
|
||||||
|
var
|
||||||
|
resAsFloat, floatProd: float64
|
||||||
|
result = a * b
|
||||||
|
floatProd = float64(a) # conversion
|
||||||
|
floatProd = floatProd * float64(b)
|
||||||
|
resAsFloat = float64(result)
|
||||||
|
|
||||||
|
# Fast path for normal case: small multiplicands, and no info
|
||||||
|
# is lost in either method.
|
||||||
|
if resAsFloat == floatProd: return result
|
||||||
|
|
||||||
|
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||||
|
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||||
|
# The difference either is or isn't significant compared to the
|
||||||
|
# true value (of which floatProd is a good approximation).
|
||||||
|
|
||||||
|
# abs(diff)/abs(prod) <= 1/32 iff
|
||||||
|
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||||
|
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
|
||||||
|
proc absInt(a: int): int {.compilerProc, inline.} =
|
||||||
|
if a != low(int):
|
||||||
|
if a >= 0: return a
|
||||||
|
else: return -a
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
when defined(I386) and (defined(vcc) or defined(wcc) or defined(dmc)):
|
||||||
|
# or defined(gcc)):
|
||||||
|
{.define: asmVersion.}
|
||||||
|
# my Version of Borland C++Builder does not have
|
||||||
|
# tasm32, which is needed for assembler blocks
|
||||||
|
# this is why Borland is not included in the 'when'
|
||||||
|
else:
|
||||||
|
{.define: useInline.}
|
||||||
|
|
||||||
|
when defined(asmVersion) and defined(gcc):
|
||||||
|
proc addInt(a, b: int): int {.compilerProc, pure, inline.}
|
||||||
|
proc subInt(a, b: int): int {.compilerProc, pure, inline.}
|
||||||
|
proc mulInt(a, b: int): int {.compilerProc, pure, inline.}
|
||||||
|
proc divInt(a, b: int): int {.compilerProc, pure, inline.}
|
||||||
|
proc modInt(a, b: int): int {.compilerProc, pure, inline.}
|
||||||
|
proc negInt(a: int): int {.compilerProc, pure, inline.}
|
||||||
|
|
||||||
|
elif defined(asmVersion):
|
||||||
|
proc addInt(a, b: int): int {.compilerProc, pure.}
|
||||||
|
proc subInt(a, b: int): int {.compilerProc, pure.}
|
||||||
|
proc mulInt(a, b: int): int {.compilerProc, pure.}
|
||||||
|
proc divInt(a, b: int): int {.compilerProc, pure.}
|
||||||
|
proc modInt(a, b: int): int {.compilerProc, pure.}
|
||||||
|
proc negInt(a: int): int {.compilerProc, pure.}
|
||||||
|
|
||||||
|
elif defined(useInline):
|
||||||
|
proc addInt(a, b: int): int {.compilerProc, inline.}
|
||||||
|
proc subInt(a, b: int): int {.compilerProc, inline.}
|
||||||
|
proc mulInt(a, b: int): int {.compilerProc.}
|
||||||
|
# mulInt is to large for inlining?
|
||||||
|
proc divInt(a, b: int): int {.compilerProc, inline.}
|
||||||
|
proc modInt(a, b: int): int {.compilerProc, inline.}
|
||||||
|
proc negInt(a: int): int {.compilerProc, inline.}
|
||||||
|
|
||||||
|
else:
|
||||||
|
proc addInt(a, b: int): int {.compilerProc.}
|
||||||
|
proc subInt(a, b: int): int {.compilerProc.}
|
||||||
|
proc mulInt(a, b: int): int {.compilerProc.}
|
||||||
|
proc divInt(a, b: int): int {.compilerProc.}
|
||||||
|
proc modInt(a, b: int): int {.compilerProc.}
|
||||||
|
proc negInt(a: int): int {.compilerProc.}
|
||||||
|
|
||||||
|
# implementation:
|
||||||
|
|
||||||
|
when defined(asmVersion) and not defined(gcc):
|
||||||
|
# assembler optimized versions for compilers that
|
||||||
|
# have an intel syntax assembler:
|
||||||
|
proc addInt(a, b: int): int =
|
||||||
|
# a in eax, and b in edx
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
add eax, `b`
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc subInt(a, b: int): int =
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
sub eax, `b`
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc negInt(a: int): int =
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
neg eax
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc divInt(a, b: int): int =
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
mov ecx, `b`
|
||||||
|
xor edx, edx
|
||||||
|
idiv ecx
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc modInt(a, b: int): int =
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
mov ecx, `b`
|
||||||
|
xor edx, edx
|
||||||
|
idiv ecx
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
mov eax, edx
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc mulInt(a, b: int): int =
|
||||||
|
asm """
|
||||||
|
mov eax, `a`
|
||||||
|
mov ecx, `b`
|
||||||
|
xor edx, edx
|
||||||
|
imul ecx
|
||||||
|
jno theEnd
|
||||||
|
call raiseOverflow
|
||||||
|
theEnd:
|
||||||
|
"""
|
||||||
|
|
||||||
|
elif defined(asmVersion) and defined(gcc):
|
||||||
|
proc addInt(a, b: int): int =
|
||||||
|
asm """ "addl %1,%%eax\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`), "r"(`b`)
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc subInt(a, b: int): int =
|
||||||
|
asm """ "subl %1,%%eax\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`), "r"(`b`)
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc negInt(a: int): int =
|
||||||
|
asm """ "negl %%eax\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`)
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc divInt(a, b: int): int =
|
||||||
|
asm """ "xorl %%edx, %%edx\n"
|
||||||
|
"idivl %%ecx\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`), "c"(`b`)
|
||||||
|
:"%edx"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc modInt(a, b: int): int =
|
||||||
|
asm """ "xorl %%edx, %%edx\n"
|
||||||
|
"idivl %%ecx\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
"movl %%edx, %%eax"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`), "c"(`b`)
|
||||||
|
:"%edx"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc mulInt(a, b: int): int =
|
||||||
|
asm """ "xorl %%edx, %%edx\n"
|
||||||
|
"imull %%ecx\n"
|
||||||
|
"jno 1\n"
|
||||||
|
"call _raiseOverflow\n"
|
||||||
|
"1: \n"
|
||||||
|
:"=a"(`a`)
|
||||||
|
:"a"(`a`), "c"(`b`)
|
||||||
|
:"%edx"
|
||||||
|
"""
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Platform independant versions of the above (slower!)
|
||||||
|
|
||||||
|
proc addInt(a, b: int): int =
|
||||||
|
result = a + b
|
||||||
|
if (result xor a) >= 0 or (result xor b) >= 0:
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc subInt(a, b: int): int =
|
||||||
|
result = a - b
|
||||||
|
if (result xor a) >= 0 or (result xor not b) >= 0:
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc negInt(a: int): int =
|
||||||
|
if a != low(int): return -a
|
||||||
|
raiseOverflow()
|
||||||
|
|
||||||
|
proc divInt(a, b: int): int =
|
||||||
|
if b == 0:
|
||||||
|
raiseDivByZero()
|
||||||
|
if a == low(int) and b == -1:
|
||||||
|
raiseOverflow()
|
||||||
|
return a div b
|
||||||
|
|
||||||
|
proc modInt(a, b: int): int =
|
||||||
|
if b == 0:
|
||||||
|
raiseDivByZero()
|
||||||
|
return a mod b
|
||||||
|
|
||||||
|
#
|
||||||
|
# This code has been inspired by Python's source code.
|
||||||
|
# The native int product x*y is either exactly right or *way* off, being
|
||||||
|
# just the last n bits of the true product, where n is the number of bits
|
||||||
|
# in an int (the delivered product is the true product plus i*2**n for
|
||||||
|
# some integer i).
|
||||||
|
#
|
||||||
|
# The native float64 product x*y is subject to three
|
||||||
|
# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
|
||||||
|
# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
|
||||||
|
# But, unlike the native int product, it's not in *range* trouble: even
|
||||||
|
# if sizeof(int)==32 (256-bit ints), the product easily fits in the
|
||||||
|
# dynamic range of a float64. So the leading 50 (or so) bits of the float64
|
||||||
|
# product are correct.
|
||||||
|
#
|
||||||
|
# We check these two ways against each other, and declare victory if
|
||||||
|
# they're approximately the same. Else, because the native int product is
|
||||||
|
# the only one that can lose catastrophic amounts of information, it's the
|
||||||
|
# native int product that must have overflowed.
|
||||||
|
#
|
||||||
|
proc mulInt(a, b: int): int =
|
||||||
|
var
|
||||||
|
resAsFloat, floatProd: float
|
||||||
|
|
||||||
|
result = a * b
|
||||||
|
floatProd = toFloat(a) * toFloat(b)
|
||||||
|
resAsFloat = toFloat(result)
|
||||||
|
|
||||||
|
# Fast path for normal case: small multiplicands, and no info
|
||||||
|
# is lost in either method.
|
||||||
|
if resAsFloat == floatProd: return result
|
||||||
|
|
||||||
|
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||||
|
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||||
|
# The difference either is or isn't significant compared to the
|
||||||
|
# true value (of which floatProd is a good approximation).
|
||||||
|
|
||||||
|
# abs(diff)/abs(prod) <= 1/32 iff
|
||||||
|
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||||
|
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
|
||||||
|
return result
|
||||||
|
raiseOverflow()
|
||||||
118
lib/assign.nim
Executable file
118
lib/assign.nim
Executable file
|
|
@ -0,0 +1,118 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
#when defined(debugGC):
|
||||||
|
# {.define: logAssign.}
|
||||||
|
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
|
||||||
|
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||||
|
var
|
||||||
|
d = cast[TAddress](dest)
|
||||||
|
s = cast[TAddress](src)
|
||||||
|
case n.kind
|
||||||
|
of nkNone: assert(false)
|
||||||
|
of nkSlot:
|
||||||
|
genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||||
|
n.typ)
|
||||||
|
of nkList:
|
||||||
|
for i in 0..n.len-1:
|
||||||
|
genericAssignAux(dest, src, n.sons[i])
|
||||||
|
of nkCase:
|
||||||
|
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||||
|
n.typ.size)
|
||||||
|
var m = selectBranch(src, n)
|
||||||
|
if m != nil: genericAssignAux(dest, src, m)
|
||||||
|
|
||||||
|
proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||||
|
var
|
||||||
|
d = cast[TAddress](dest)
|
||||||
|
s = cast[TAddress](src)
|
||||||
|
|
||||||
|
assert(mt != nil)
|
||||||
|
case mt.Kind
|
||||||
|
of tySequence:
|
||||||
|
var s2 = cast[ppointer](src)^
|
||||||
|
var seq = cast[PGenericSeq](s2)
|
||||||
|
if s2 == nil: # this can happen! nil sequences are allowed
|
||||||
|
var x = cast[ppointer](dest)
|
||||||
|
x^ = nil
|
||||||
|
return
|
||||||
|
assert(dest != nil)
|
||||||
|
unsureAsgnRef(cast[ppointer](dest),
|
||||||
|
newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
||||||
|
var dst = cast[taddress](cast[ppointer](dest)^)
|
||||||
|
for i in 0..seq.len-1:
|
||||||
|
genericAssign(
|
||||||
|
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||||
|
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
|
||||||
|
GenericSeqSize),
|
||||||
|
mt.Base)
|
||||||
|
var dstseq = cast[PGenericSeq](dst)
|
||||||
|
dstseq.len = seq.len
|
||||||
|
dstseq.space = seq.len
|
||||||
|
of tyRecord, tyObject, tyTuple:
|
||||||
|
genericAssignAux(dest, src, mt.node)
|
||||||
|
of tyArray, tyArrayConstr:
|
||||||
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
|
genericAssign(cast[pointer](d +% i*% mt.base.size),
|
||||||
|
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||||
|
of tyString: # a leaf
|
||||||
|
var s2 = cast[ppointer](s)^
|
||||||
|
if s2 != nil: # nil strings are possible!
|
||||||
|
unsureAsgnRef(cast[ppointer](dest), copyString(cast[mstring](s2)))
|
||||||
|
else:
|
||||||
|
var x = cast[ppointer](dest)
|
||||||
|
x^ = nil
|
||||||
|
return
|
||||||
|
of tyRef: # BUGFIX: a long time this has been forgotten!
|
||||||
|
unsureAsgnRef(cast[ppointer](dest), cast[ppointer](s)^)
|
||||||
|
else:
|
||||||
|
copyMem(dest, src, mt.size) # copy raw bits
|
||||||
|
|
||||||
|
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
|
||||||
|
genericAssign(dest, addr(src), mt)
|
||||||
|
|
||||||
|
proc genericAssignOpenArray(dest, src: pointer, len: int,
|
||||||
|
mt: PNimType) {.compilerproc.} =
|
||||||
|
var
|
||||||
|
d = cast[TAddress](dest)
|
||||||
|
s = cast[TAddress](src)
|
||||||
|
for i in 0..len-1:
|
||||||
|
genericAssign(cast[pointer](d +% i*% mt.base.size),
|
||||||
|
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||||
|
|
||||||
|
proc objectInit(dest: Pointer, typ: PNimType) {.compilerProc.}
|
||||||
|
proc objectInitAux(dest: Pointer, n: ptr TNimNode) =
|
||||||
|
var d = cast[TAddress](dest)
|
||||||
|
case n.kind
|
||||||
|
of nkNone: assert(false)
|
||||||
|
of nkSLot: objectInit(cast[pointer](d +% n.offset), n.typ)
|
||||||
|
of nkList:
|
||||||
|
for i in 0..n.len-1:
|
||||||
|
objectInitAux(dest, n.sons[i])
|
||||||
|
of nkCase:
|
||||||
|
var m = selectBranch(dest, n)
|
||||||
|
if m != nil: objectInitAux(dest, m)
|
||||||
|
|
||||||
|
proc objectInit(dest: Pointer, typ: PNimType) =
|
||||||
|
# the generic init proc that takes care of initialization of complex
|
||||||
|
# objects on the stack or heap
|
||||||
|
var d = cast[TAddress](dest)
|
||||||
|
case typ.kind
|
||||||
|
of tyObject:
|
||||||
|
# iterate over any structural type
|
||||||
|
# here we have to init the type field:
|
||||||
|
var pint = cast[ptr PNimType](dest)
|
||||||
|
pint^ = typ
|
||||||
|
objectInitAux(dest, typ.node)
|
||||||
|
of tyRecord:
|
||||||
|
objectInitAux(dest, typ.node)
|
||||||
|
of tyArray, tyArrayConstr:
|
||||||
|
for i in 0..(typ.size div typ.base.size)-1:
|
||||||
|
objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
|
||||||
|
else: nil # nothing to do
|
||||||
698
lib/base/cairo/cairo.nim
Normal file
698
lib/base/cairo/cairo.nim
Normal file
|
|
@ -0,0 +1,698 @@
|
||||||
|
|
||||||
|
#* cairo - a vector graphics library with display and print output
|
||||||
|
# *
|
||||||
|
# * Copyright © 2002 University of Southern California
|
||||||
|
# * Copyright © 2005 Red Hat, Inc.
|
||||||
|
# *
|
||||||
|
# * This library is free software; you can redistribute it and/or
|
||||||
|
# * modify it either under the terms of the GNU Lesser General Public
|
||||||
|
# * License version 2.1 as published by the Free Software Foundation
|
||||||
|
# * (the "LGPL") or, at your option, under the terms of the Mozilla
|
||||||
|
# * Public License Version 1.1 (the "MPL"). If you do not alter this
|
||||||
|
# * notice, a recipient may use your version of this file under either
|
||||||
|
# * the MPL or the LGPL.
|
||||||
|
# *
|
||||||
|
# * You should have received a copy of the LGPL along with this library
|
||||||
|
# * in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
||||||
|
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
# * You should have received a copy of the MPL along with this library
|
||||||
|
# * in the file COPYING-MPL-1.1
|
||||||
|
# *
|
||||||
|
# * The contents of this file are subject to the Mozilla Public License
|
||||||
|
# * Version 1.1 (the "License"); you may not use this file except in
|
||||||
|
# * compliance with the License. You may obtain a copy of the License at
|
||||||
|
# * http://www.mozilla.org/MPL/
|
||||||
|
# *
|
||||||
|
# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
||||||
|
# * OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
||||||
|
# * the specific language governing rights and limitations.
|
||||||
|
# *
|
||||||
|
# * The Original Code is the cairo graphics library.
|
||||||
|
# *
|
||||||
|
# * The Initial Developer of the Original Code is University of Southern
|
||||||
|
# * California.
|
||||||
|
# *
|
||||||
|
# * Contributor(s):
|
||||||
|
# * Carl D. Worth <cworth@cworth.org>
|
||||||
|
# #*
|
||||||
|
# * This FreePascal binding generated August 26, 2005
|
||||||
|
# * by Jeffrey Pohlmeyer <yetanothergeek@yahoo.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# - Updated to cairo version 1.4
|
||||||
|
# - Grouped OS specific fuctions in separated units
|
||||||
|
# - Organized the functions by group and ordered exactly as the c header
|
||||||
|
# - Cleared parameter list syntax according to pascal standard
|
||||||
|
#
|
||||||
|
# By Luiz Américo Pereira Câmara
|
||||||
|
# October 2007
|
||||||
|
#
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
const
|
||||||
|
LIB_CAIRO* = "cairo.dll"
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
LIB_CAIRO* = "libcairo.so"
|
||||||
|
|
||||||
|
type
|
||||||
|
PByte = cstring
|
||||||
|
cairo_status_t* = enum
|
||||||
|
CAIRO_STATUS_SUCCESS = 0, CAIRO_STATUS_NO_MEMORY,
|
||||||
|
CAIRO_STATUS_INVALID_RESTORE, CAIRO_STATUS_INVALID_POP_GROUP,
|
||||||
|
CAIRO_STATUS_NO_CURRENT_POINT, CAIRO_STATUS_INVALID_MATRIX,
|
||||||
|
CAIRO_STATUS_INVALID_STATUS, CAIRO_STATUS_NULL_POINTER,
|
||||||
|
CAIRO_STATUS_INVALID_STRING, CAIRO_STATUS_INVALID_PATH_DATA,
|
||||||
|
CAIRO_STATUS_READ_ERROR, CAIRO_STATUS_WRITE_ERROR,
|
||||||
|
CAIRO_STATUS_SURFACE_FINISHED, CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
|
||||||
|
CAIRO_STATUS_PATTERN_TYPE_MISMATCH, CAIRO_STATUS_INVALID_CONTENT,
|
||||||
|
CAIRO_STATUS_INVALID_FORMAT, CAIRO_STATUS_INVALID_VISUAL,
|
||||||
|
CAIRO_STATUS_FILE_NOT_FOUND, CAIRO_STATUS_INVALID_DASH
|
||||||
|
cairo_operator_t* = enum
|
||||||
|
CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SOURCE, CAIRO_OPERATOR_OVER,
|
||||||
|
CAIRO_OPERATOR_IN, CAIRO_OPERATOR_OUT, CAIRO_OPERATOR_ATOP,
|
||||||
|
CAIRO_OPERATOR_DEST, CAIRO_OPERATOR_DEST_OVER, CAIRO_OPERATOR_DEST_IN,
|
||||||
|
CAIRO_OPERATOR_DEST_OUT, CAIRO_OPERATOR_DEST_ATOP, CAIRO_OPERATOR_XOR,
|
||||||
|
CAIRO_OPERATOR_ADD, CAIRO_OPERATOR_SATURATE
|
||||||
|
cairo_antialias_t* = enum
|
||||||
|
CAIRO_ANTIALIAS_DEFAULT, CAIRO_ANTIALIAS_NONE, CAIRO_ANTIALIAS_GRAY,
|
||||||
|
CAIRO_ANTIALIAS_SUBPIXEL
|
||||||
|
cairo_fill_rule_t* = enum
|
||||||
|
CAIRO_FILL_RULE_WINDING, CAIRO_FILL_RULE_EVEN_ODD
|
||||||
|
cairo_line_cap_t* = enum
|
||||||
|
CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE
|
||||||
|
cairo_line_join_t* = enum
|
||||||
|
CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_ROUND, CAIRO_LINE_JOIN_BEVEL
|
||||||
|
cairo_font_slant_t* = enum
|
||||||
|
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_SLANT_OBLIQUE
|
||||||
|
cairo_font_weight_t* = enum
|
||||||
|
CAIRO_FONT_WEIGHT_NORMAL, CAIRO_FONT_WEIGHT_BOLD
|
||||||
|
cairo_subpixel_order_t* = enum
|
||||||
|
CAIRO_SUBPIXEL_ORDER_DEFAULT, CAIRO_SUBPIXEL_ORDER_RGB,
|
||||||
|
CAIRO_SUBPIXEL_ORDER_BGR, CAIRO_SUBPIXEL_ORDER_VRGB,
|
||||||
|
CAIRO_SUBPIXEL_ORDER_VBGR
|
||||||
|
cairo_hint_style_t* = enum
|
||||||
|
CAIRO_HINT_STYLE_DEFAULT, CAIRO_HINT_STYLE_NONE, CAIRO_HINT_STYLE_SLIGHT,
|
||||||
|
CAIRO_HINT_STYLE_MEDIUM, CAIRO_HINT_STYLE_FULL
|
||||||
|
cairo_hint_metrics_t* = enum
|
||||||
|
CAIRO_HINT_METRICS_DEFAULT, CAIRO_HINT_METRICS_OFF, CAIRO_HINT_METRICS_ON
|
||||||
|
cairo_path_data_type_t* = enum
|
||||||
|
CAIRO_PATH_MOVE_TO, CAIRO_PATH_LINE_TO, CAIRO_PATH_CURVE_TO,
|
||||||
|
CAIRO_PATH_CLOSE_PATH
|
||||||
|
cairo_content_t* = enum
|
||||||
|
CAIRO_CONTENT_COLOR = 0x00001000, CAIRO_CONTENT_ALPHA = 0x00002000,
|
||||||
|
CAIRO_CONTENT_COLOR_ALPHA = 0x00003000
|
||||||
|
cairo_format_t* = enum
|
||||||
|
CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_RGB24, CAIRO_FORMAT_A8, CAIRO_FORMAT_A1
|
||||||
|
cairo_extend_t* = enum
|
||||||
|
CAIRO_EXTEND_NONE, CAIRO_EXTEND_REPEAT, CAIRO_EXTEND_REFLECT,
|
||||||
|
CAIRO_EXTEND_PAD
|
||||||
|
cairo_filter_t* = enum
|
||||||
|
CAIRO_FILTER_FAST, CAIRO_FILTER_GOOD, CAIRO_FILTER_BEST,
|
||||||
|
CAIRO_FILTER_NEAREST, CAIRO_FILTER_BILINEAR, CAIRO_FILTER_GAUSSIAN
|
||||||
|
cairo_font_type_t* = enum
|
||||||
|
CAIRO_FONT_TYPE_TOY, CAIRO_FONT_TYPE_FT, CAIRO_FONT_TYPE_WIN32,
|
||||||
|
CAIRO_FONT_TYPE_ATSUI
|
||||||
|
cairo_pattern_type_t* = enum
|
||||||
|
CAIRO_PATTERN_TYPE_SOLID, CAIRO_PATTERN_TYPE_SURFACE,
|
||||||
|
CAIRO_PATTERN_TYPE_LINEAR, CAIRO_PATTERN_TYPE_RADIAL
|
||||||
|
cairo_surface_type_t* = enum
|
||||||
|
CAIRO_SURFACE_TYPE_IMAGE, CAIRO_SURFACE_TYPE_PDF, CAIRO_SURFACE_TYPE_PS,
|
||||||
|
CAIRO_SURFACE_TYPE_XLIB, CAIRO_SURFACE_TYPE_XCB, CAIRO_SURFACE_TYPE_GLITZ,
|
||||||
|
CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_SURFACE_TYPE_WIN32,
|
||||||
|
CAIRO_SURFACE_TYPE_BEOS, CAIRO_SURFACE_TYPE_DIRECTFB,
|
||||||
|
CAIRO_SURFACE_TYPE_SVG, CAIRO_SURFACE_TYPE_OS2
|
||||||
|
cairo_svg_version_t* = enum
|
||||||
|
CAIRO_SVG_VERSION_1_1, CAIRO_SVG_VERSION_1_2
|
||||||
|
Pcairo_surface_t* = ref cairo_surface_t
|
||||||
|
PPcairo_surface_t* = ref Pcairo_surface_t
|
||||||
|
Pcairo_t* = ref cairo_t
|
||||||
|
Pcairo_pattern_t* = ref cairo_pattern_t
|
||||||
|
Pcairo_font_options_t* = ref cairo_font_options_t
|
||||||
|
Pcairo_font_face_t* = ref cairo_font_face_t
|
||||||
|
Pcairo_scaled_font_t* = ref cairo_scaled_font_t
|
||||||
|
Pcairo_bool_t* = ref cairo_bool_t
|
||||||
|
cairo_bool_t* = int32
|
||||||
|
Pcairo_matrix_t* = ref cairo_matrix_t
|
||||||
|
Pcairo_user_data_key_t* = ref cairo_user_data_key_t
|
||||||
|
Pcairo_glyph_t* = ref cairo_glyph_t
|
||||||
|
Pcairo_text_extents_t* = ref cairo_text_extents_t
|
||||||
|
Pcairo_font_extents_t* = ref cairo_font_extents_t
|
||||||
|
Pcairo_path_data_type_t* = ref cairo_path_data_type_t
|
||||||
|
Pcairo_path_data_t* = ref cairo_path_data_t
|
||||||
|
Pcairo_path_t* = ref cairo_path_t
|
||||||
|
Pcairo_rectangle_t* = ref cairo_rectangle_t
|
||||||
|
Pcairo_rectangle_list_t* = ref cairo_rectangle_list_t
|
||||||
|
cairo_destroy_func_t* = proc (data: Pointer){.cdecl.}
|
||||||
|
cairo_write_func_t* = proc (closure: Pointer, data: PByte, len: int32): cairo_status_t{.
|
||||||
|
cdecl.}
|
||||||
|
cairo_read_func_t* = proc (closure: Pointer, data: PByte, len: int32): cairo_status_t{.
|
||||||
|
cdecl.}
|
||||||
|
cairo_t* = record #OPAQUE
|
||||||
|
cairo_surface_t* = record #OPAQUE
|
||||||
|
cairo_pattern_t* = record #OPAQUE
|
||||||
|
cairo_scaled_font_t* = record #OPAQUE
|
||||||
|
cairo_font_face_t* = record #OPAQUE
|
||||||
|
cairo_font_options_t* = record #OPAQUE
|
||||||
|
cairo_matrix_t* = record
|
||||||
|
xx: float64
|
||||||
|
yx: float64
|
||||||
|
xy: float64
|
||||||
|
yy: float64
|
||||||
|
x0: float64
|
||||||
|
y0: float64
|
||||||
|
|
||||||
|
cairo_user_data_key_t* = record
|
||||||
|
unused: int32
|
||||||
|
|
||||||
|
cairo_glyph_t* = record
|
||||||
|
index: int32
|
||||||
|
x: float64
|
||||||
|
y: float64
|
||||||
|
|
||||||
|
cairo_text_extents_t* = record
|
||||||
|
x_bearing: float64
|
||||||
|
y_bearing: float64
|
||||||
|
width: float64
|
||||||
|
height: float64
|
||||||
|
x_advance: float64
|
||||||
|
y_advance: float64
|
||||||
|
|
||||||
|
cairo_font_extents_t* = record
|
||||||
|
ascent: float64
|
||||||
|
descent: float64
|
||||||
|
height: float64
|
||||||
|
max_x_advance: float64
|
||||||
|
max_y_advance: float64
|
||||||
|
|
||||||
|
cairo_path_data_t* = record #* _type : cairo_path_data_type_t;
|
||||||
|
# length : LongInt;
|
||||||
|
# end
|
||||||
|
x: float64
|
||||||
|
y: float64
|
||||||
|
|
||||||
|
cairo_path_t* = record
|
||||||
|
status: cairo_status_t
|
||||||
|
data: Pcairo_path_data_t
|
||||||
|
num_data: int32
|
||||||
|
|
||||||
|
cairo_rectangle_t* = record
|
||||||
|
x, y, width, height: float64
|
||||||
|
|
||||||
|
cairo_rectangle_list_t* = record
|
||||||
|
status: cairo_status_t
|
||||||
|
rectangles: Pcairo_rectangle_t
|
||||||
|
num_rectangles: int32
|
||||||
|
|
||||||
|
|
||||||
|
proc cairo_version*(): int32{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_version_string*(): cstring{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#Helper function to retrieve decoded version
|
||||||
|
proc cairo_version*(major, minor, micro: var int32)
|
||||||
|
#* Functions for manipulating state objects
|
||||||
|
proc cairo_create*(target: Pcairo_surface_t): Pcairo_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_reference*(cr: Pcairo_t): Pcairo_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_destroy*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_reference_count*(cr: Pcairo_t): int32{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_user_data*(cr: Pcairo_t, key: Pcairo_user_data_key_t): pointer{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_user_data*(cr: PCairo_t, key: Pcairo_user_data_key_t,
|
||||||
|
user_data: Pointer, destroy: cairo_destroy_func_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_save*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_restore*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_push_group*(cr: PCairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_push_group_with_content*(cr: PCairo_t, content: cairo_content_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pop_group*(cr: PCairo_t): Pcairo_pattern_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pop_group_to_source*(cr: PCairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Modify state
|
||||||
|
proc cairo_set_operator*(cr: Pcairo_t, op: cairo_operator_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_source*(cr: Pcairo_t, source: Pcairo_pattern_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_source_rgb*(cr: Pcairo_t, red, green, blue: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_source_rgba*(cr: Pcairo_t, red, green, blue, alpha: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_source_surface*(cr: Pcairo_t, surface: Pcairo_surface_t,
|
||||||
|
x, y: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_tolerance*(cr: Pcairo_t, tolerance: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_antialias*(cr: Pcairo_t, antialias: cairo_antialias_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_fill_rule*(cr: Pcairo_t, fill_rule: cairo_fill_rule_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_line_width*(cr: Pcairo_t, width: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_line_cap*(cr: Pcairo_t, line_cap: cairo_line_cap_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_line_join*(cr: Pcairo_t, line_join: cairo_line_join_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_dash*(cr: Pcairo_t, dashes: openarray[float64],
|
||||||
|
offset: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_miter_limit*(cr: Pcairo_t, limit: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_translate*(cr: Pcairo_t, tx, ty: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scale*(cr: Pcairo_t, sx, sy: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rotate*(cr: Pcairo_t, angle: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_transform*(cr: Pcairo_t, matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_matrix*(cr: Pcairo_t, matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_identity_matrix*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_user_to_device*(cr: Pcairo_t, x, y: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_user_to_device_distance*(cr: Pcairo_t, dx, dy: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_device_to_user*(cr: Pcairo_t, x, y: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_device_to_user_distance*(cr: Pcairo_t, dx, dy: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Path creation functions
|
||||||
|
proc cairo_new_path*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_move_to*(cr: Pcairo_t, x, y: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_new_sub_path*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_line_to*(cr: Pcairo_t, x, y: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_curve_to*(cr: Pcairo_t, x1, y1, x2, y2, x3, y3: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_arc*(cr: Pcairo_t, xc, yc, radius, angle1, angle2: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_arc_negative*(cr: Pcairo_t, xc, yc, radius, angle1, angle2: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rel_move_to*(cr: Pcairo_t, dx, dy: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rel_line_to*(cr: Pcairo_t, dx, dy: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rel_curve_to*(cr: Pcairo_t, dx1, dy1, dx2, dy2, dx3, dy3: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rectangle*(cr: Pcairo_t, x, y, width, height: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_close_path*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Painting functions
|
||||||
|
proc cairo_paint*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_paint_with_alpha*(cr: Pcairo_t, alpha: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_mask*(cr: Pcairo_t, pattern: Pcairo_pattern_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_mask_surface*(cr: Pcairo_t, surface: Pcairo_surface_t,
|
||||||
|
surface_x, surface_y: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_stroke*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_stroke_preserve*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_fill*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_fill_preserve*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_copy_page*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_show_page*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Insideness testing
|
||||||
|
proc cairo_in_stroke*(cr: Pcairo_t, x, y: float64): cairo_bool_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_in_fill*(cr: Pcairo_t, x, y: float64): cairo_bool_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Rectangular extents
|
||||||
|
proc cairo_stroke_extents*(cr: Pcairo_t, x1, y1, x2, y2: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_fill_extents*(cr: Pcairo_t, x1, y1, x2, y2: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Clipping
|
||||||
|
proc cairo_reset_clip*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_clip*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_clip_preserve*(cr: Pcairo_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_clip_extents*(cr: Pcairo_t, x1, y1, x2, y2: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_copy_clip_rectangle_list*(cr: Pcairo_t): Pcairo_rectangle_list_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_rectangle_list_destroy*(rectangle_list: Pcairo_rectangle_list_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Font/Text functions
|
||||||
|
proc cairo_font_options_create*(): Pcairo_font_options_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_copy*(original: Pcairo_font_options_t): Pcairo_font_options_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_destroy*(options: Pcairo_font_options_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_status*(options: Pcairo_font_options_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_merge*(options, other: Pcairo_font_options_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_equal*(options, other: Pcairo_font_options_t): cairo_bool_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_hash*(options: Pcairo_font_options_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_set_antialias*(options: Pcairo_font_options_t,
|
||||||
|
antialias: cairo_antialias_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_get_antialias*(options: Pcairo_font_options_t): cairo_antialias_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_set_subpixel_order*(options: Pcairo_font_options_t,
|
||||||
|
subpixel_order: cairo_subpixel_order_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_get_subpixel_order*(options: Pcairo_font_options_t): cairo_subpixel_order_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_set_hint_style*(options: Pcairo_font_options_t,
|
||||||
|
hint_style: cairo_hint_style_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_get_hint_style*(options: Pcairo_font_options_t): cairo_hint_style_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_set_hint_metrics*(options: Pcairo_font_options_t,
|
||||||
|
hint_metrics: cairo_hint_metrics_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_options_get_hint_metrics*(options: Pcairo_font_options_t): cairo_hint_metrics_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* This interface is for dealing with text as text, not caring about the
|
||||||
|
# font object inside the the cairo_t.
|
||||||
|
proc cairo_select_font_face*(cr: Pcairo_t, family: cstring,
|
||||||
|
slant: cairo_font_slant_t,
|
||||||
|
weight: cairo_font_weight_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_font_size*(cr: Pcairo_t, size: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_font_matrix*(cr: Pcairo_t, matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_font_matrix*(cr: Pcairo_t, matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_font_options*(cr: Pcairo_t, options: Pcairo_font_options_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_font_options*(cr: Pcairo_t, options: Pcairo_font_options_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_font_face*(cr: Pcairo_t, font_face: Pcairo_font_face_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_font_face*(cr: Pcairo_t): Pcairo_font_face_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_set_scaled_font*(cr: PCairo_t, scaled_font: Pcairo_scaled_font_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_scaled_font*(cr: Pcairo_t): Pcairo_scaled_font_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_show_text*(cr: Pcairo_t, utf8: cstring){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_show_glyphs*(cr: Pcairo_t, glyphs: Pcairo_glyph_t, num_glyphs: int32){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_text_path*(cr: Pcairo_t, utf8: cstring){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_glyph_path*(cr: Pcairo_t, glyphs: Pcairo_glyph_t, num_glyphs: int32){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_text_extents*(cr: Pcairo_t, utf8: cstring,
|
||||||
|
extents: Pcairo_text_extents_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_glyph_extents*(cr: Pcairo_t, glyphs: Pcairo_glyph_t,
|
||||||
|
num_glyphs: int32, extents: Pcairo_text_extents_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_extents*(cr: Pcairo_t, extents: Pcairo_font_extents_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Generic identifier for a font style
|
||||||
|
proc cairo_font_face_reference*(font_face: Pcairo_font_face_t): Pcairo_font_face_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_destroy*(font_face: Pcairo_font_face_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_get_reference_count*(font_face: Pcairo_font_face_t): int32{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_status*(font_face: Pcairo_font_face_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_get_type*(font_face: Pcairo_font_face_t): cairo_font_type_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_get_user_data*(font_face: Pcairo_font_face_t,
|
||||||
|
key: Pcairo_user_data_key_t): pointer{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_font_face_set_user_data*(font_face: Pcairo_font_face_t,
|
||||||
|
key: Pcairo_user_data_key_t,
|
||||||
|
user_data: pointer,
|
||||||
|
destroy: cairo_destroy_func_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Portable interface to general font features
|
||||||
|
proc cairo_scaled_font_create*(font_face: Pcairo_font_face_t,
|
||||||
|
font_matrix: Pcairo_matrix_t,
|
||||||
|
ctm: Pcairo_matrix_t,
|
||||||
|
options: Pcairo_font_options_t): Pcairo_scaled_font_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_reference*(scaled_font: Pcairo_scaled_font_t): Pcairo_scaled_font_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_destroy*(scaled_font: Pcairo_scaled_font_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_reference_count*(scaled_font: Pcairo_scaled_font_t): int32{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_status*(scaled_font: Pcairo_scaled_font_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_type*(scaled_font: Pcairo_scaled_font_t): cairo_font_type_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_user_data*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
key: Pcairo_user_data_key_t): Pointer{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_set_user_data*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
key: Pcairo_user_data_key_t,
|
||||||
|
user_data: Pointer,
|
||||||
|
destroy: cairo_destroy_func_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_extents*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
extents: Pcairo_font_extents_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_text_extents*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
utf8: cstring,
|
||||||
|
extents: Pcairo_text_extents_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_glyph_extents*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
glyphs: Pcairo_glyph_t, num_glyphs: int32,
|
||||||
|
extents: Pcairo_text_extents_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_font_face*(scaled_font: Pcairo_scaled_font_t): Pcairo_font_face_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_font_matrix*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
font_matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_ctm*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
ctm: Pcairo_matrix_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_scaled_font_get_font_options*(scaled_font: Pcairo_scaled_font_t,
|
||||||
|
options: Pcairo_font_options_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Query functions
|
||||||
|
proc cairo_get_operator*(cr: Pcairo_t): cairo_operator_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_source*(cr: Pcairo_t): Pcairo_pattern_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_tolerance*(cr: Pcairo_t): float64{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_antialias*(cr: Pcairo_t): cairo_antialias_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_current_point*(cr: Pcairo_t, x, y: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_fill_rule*(cr: Pcairo_t): cairo_fill_rule_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_line_width*(cr: Pcairo_t): float64{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_line_cap*(cr: Pcairo_t): cairo_line_cap_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_line_join*(cr: Pcairo_t): cairo_line_join_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_miter_limit*(cr: Pcairo_t): float64{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_dash_count*(cr: Pcairo_t): int32{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_dash*(cr: Pcairo_t, dashes, offset: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_matrix*(cr: Pcairo_t, matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_target*(cr: Pcairo_t): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_get_group_target*(cr: Pcairo_t): Pcairo_surface_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_copy_path*(cr: Pcairo_t): Pcairo_path_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_copy_path_flat*(cr: Pcairo_t): Pcairo_path_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_append_path*(cr: Pcairo_t, path: Pcairo_path_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_path_destroy*(path: Pcairo_path_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Error status queries
|
||||||
|
proc cairo_status*(cr: Pcairo_t): cairo_status_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_status_to_string*(status: cairo_status_t): cstring{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Surface manipulation
|
||||||
|
proc cairo_surface_create_similar*(other: Pcairo_surface_t,
|
||||||
|
content: cairo_content_t,
|
||||||
|
width, height: int32): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_reference*(surface: Pcairo_surface_t): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_finish*(surface: Pcairo_surface_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_destroy*(surface: Pcairo_surface_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_reference_count*(surface: Pcairo_surface_t): int32{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_status*(surface: Pcairo_surface_t): cairo_status_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_type*(surface: Pcairo_surface_t): cairo_surface_type_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_content*(surface: Pcairo_surface_t): cairo_content_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_write_to_png*(surface: Pcairo_surface_t, filename: cstring): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_write_to_png_stream*(surface: Pcairo_surface_t,
|
||||||
|
write_func: cairo_write_func_t,
|
||||||
|
closure: pointer): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_user_data*(surface: Pcairo_surface_t,
|
||||||
|
key: Pcairo_user_data_key_t): pointer{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_set_user_data*(surface: Pcairo_surface_t,
|
||||||
|
key: Pcairo_user_data_key_t,
|
||||||
|
user_data: pointer,
|
||||||
|
destroy: cairo_destroy_func_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_font_options*(surface: Pcairo_surface_t,
|
||||||
|
options: Pcairo_font_options_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_flush*(surface: Pcairo_surface_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_mark_dirty*(surface: Pcairo_surface_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_mark_dirty_rectangle*(surface: Pcairo_surface_t,
|
||||||
|
x, y, width, height: int32){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_set_device_offset*(surface: Pcairo_surface_t,
|
||||||
|
x_offset, y_offset: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_get_device_offset*(surface: Pcairo_surface_t,
|
||||||
|
x_offset, y_offset: var float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_surface_set_fallback_resolution*(surface: Pcairo_surface_t,
|
||||||
|
x_pixels_per_inch, y_pixels_per_inch: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Image-surface functions
|
||||||
|
proc cairo_image_surface_create*(format: cairo_format_t, width, height: int32): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_create_for_data*(data: Pbyte, format: cairo_format_t,
|
||||||
|
width, height, stride: int32): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_get_data*(surface: Pcairo_surface_t): cstring{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_get_format*(surface: Pcairo_surface_t): cairo_format_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_get_width*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_get_height*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_get_stride*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_create_from_png*(filename: cstring): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_image_surface_create_from_png_stream*(read_func: cairo_read_func_t,
|
||||||
|
closure: pointer): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Pattern creation functions
|
||||||
|
proc cairo_pattern_create_rgb*(red, green, blue: float64): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_create_rgba*(red, green, blue, alpha: float64): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_create_for_surface*(surface: Pcairo_surface_t): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_create_linear*(x0, y0, x1, y1: float64): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_create_radial*(cx0, cy0, radius0, cx1, cy1, radius1: float64): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_reference*(pattern: Pcairo_pattern_t): Pcairo_pattern_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_destroy*(pattern: Pcairo_pattern_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_reference_count*(pattern: Pcairo_pattern_t): int32{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_status*(pattern: Pcairo_pattern_t): cairo_status_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_user_data*(pattern: Pcairo_pattern_t,
|
||||||
|
key: Pcairo_user_data_key_t): Pointer{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_set_user_data*(pattern: Pcairo_pattern_t,
|
||||||
|
key: Pcairo_user_data_key_t,
|
||||||
|
user_data: Pointer,
|
||||||
|
destroy: cairo_destroy_func_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_type*(pattern: Pcairo_pattern_t): cairo_pattern_type_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_add_color_stop_rgb*(pattern: Pcairo_pattern_t,
|
||||||
|
offset, red, green, blue: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_add_color_stop_rgba*(pattern: Pcairo_pattern_t, offset, red,
|
||||||
|
green, blue, alpha: float64){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_set_matrix*(pattern: Pcairo_pattern_t,
|
||||||
|
matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_matrix*(pattern: Pcairo_pattern_t,
|
||||||
|
matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_set_extend*(pattern: Pcairo_pattern_t, extend: cairo_extend_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_extend*(pattern: Pcairo_pattern_t): cairo_extend_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_set_filter*(pattern: Pcairo_pattern_t, filter: cairo_filter_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_filter*(pattern: Pcairo_pattern_t): cairo_filter_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_rgba*(pattern: Pcairo_pattern_t,
|
||||||
|
red, green, blue, alpha: var float64): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_surface*(pattern: Pcairo_pattern_t,
|
||||||
|
surface: PPcairo_surface_t): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_color_stop_rgba*(pattern: Pcairo_pattern_t, index: int32,
|
||||||
|
offset, red, green, blue, alpha: var float64): cairo_status_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_color_stop_count*(pattern: Pcairo_pattern_t,
|
||||||
|
count: var int32): cairo_status_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_linear_points*(pattern: Pcairo_pattern_t,
|
||||||
|
x0, y0, x1, y1: var float64): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pattern_get_radial_circles*(pattern: Pcairo_pattern_t,
|
||||||
|
x0, y0, r0, x1, y1, r1: var float64): cairo_status_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* Matrix functions
|
||||||
|
proc cairo_matrix_init*(matrix: Pcairo_matrix_t, xx, yx, xy, yy, x0, y0: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_init_identity*(matrix: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_init_translate*(matrix: Pcairo_matrix_t, tx, ty: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_init_scale*(matrix: Pcairo_matrix_t, sx, sy: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_init_rotate*(matrix: Pcairo_matrix_t, radians: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_translate*(matrix: Pcairo_matrix_t, tx, ty: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_scale*(matrix: Pcairo_matrix_t, sx, sy: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_rotate*(matrix: Pcairo_matrix_t, radians: float64){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_invert*(matrix: Pcairo_matrix_t): cairo_status_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_multiply*(result, a, b: Pcairo_matrix_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_transform_distance*(matrix: Pcairo_matrix_t, dx, dy: var float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_matrix_transform_point*(matrix: Pcairo_matrix_t, x, y: var float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* PDF functions
|
||||||
|
proc cairo_pdf_surface_create*(filename: cstring,
|
||||||
|
width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pdf_surface_create_for_stream*(write_func: cairo_write_func_t,
|
||||||
|
closure: Pointer, width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_pdf_surface_set_size*(surface: Pcairo_surface_t,
|
||||||
|
width_in_points, height_in_points: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#* PS functions
|
||||||
|
proc cairo_ps_surface_create*(filename: cstring,
|
||||||
|
width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ps_surface_create_for_stream*(write_func: cairo_write_func_t,
|
||||||
|
closure: Pointer, width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ps_surface_set_size*(surface: Pcairo_surface_t,
|
||||||
|
width_in_points, height_in_points: float64){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ps_surface_dsc_comment*(surface: Pcairo_surface_t, comment: cstring){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ps_surface_dsc_begin_setup*(surface: Pcairo_surface_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ps_surface_dsc_begin_page_setup*(surface: Pcairo_surface_t){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* SVG functions
|
||||||
|
proc cairo_svg_surface_create*(filename: cstring,
|
||||||
|
width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_svg_surface_create_for_stream*(write_func: cairo_write_func_t,
|
||||||
|
closure: Pointer, width_in_points, height_in_points: float64): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_svg_surface_restrict_to_version*(surface: Pcairo_surface_t,
|
||||||
|
version: cairo_svg_version_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
#todo: see how translate this
|
||||||
|
#procedure cairo_svg_get_versions(cairo_svg_version_t const **versions,
|
||||||
|
# int *num_versions);
|
||||||
|
proc cairo_svg_version_to_string*(version: cairo_svg_version_t): cstring{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
#* Functions to be used while debugging (not intended for use in production code)
|
||||||
|
proc cairo_debug_reset_static_data*(){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
# implementation
|
||||||
|
|
||||||
|
proc cairo_version(major, minor, micro: var int32) =
|
||||||
|
var version: int32
|
||||||
|
version = cairo_version()
|
||||||
|
major = version div 10000
|
||||||
|
minor = (version mod (major * 10000)) div 100
|
||||||
|
micro = (version mod ((major * 10000) + (minor * 100)))
|
||||||
36
lib/base/cairo/cairoft.nim
Normal file
36
lib/base/cairo/cairoft.nim
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#
|
||||||
|
# Translation of cairo-ft.h
|
||||||
|
# by Jeffrey Pohlmeyer
|
||||||
|
# updated to version 1.4 by Luiz Américo Pereira Câmara 2007
|
||||||
|
#
|
||||||
|
|
||||||
|
import Cairo, freetypeh
|
||||||
|
|
||||||
|
#todo: properly define FcPattern:
|
||||||
|
#It will require translate FontConfig header
|
||||||
|
|
||||||
|
#*
|
||||||
|
#typedef struct _XftPattern {
|
||||||
|
# int num;
|
||||||
|
# int size;
|
||||||
|
# XftPatternElt *elts;
|
||||||
|
# } XftPattern;
|
||||||
|
# typedef FcPattern XftPattern;
|
||||||
|
#
|
||||||
|
|
||||||
|
type
|
||||||
|
FcPattern* = Pointer
|
||||||
|
PFcPattern* = ref FcPattern
|
||||||
|
|
||||||
|
proc cairo_ft_font_face_create_for_pattern*(pattern: PFcPattern): Pcairo_font_face_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ft_font_options_substitute*(options: Pcairo_font_options_t,
|
||||||
|
pattern: PFcPattern){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ft_font_face_create_for_ft_face*(face: TFT_Face,
|
||||||
|
load_flags: int32): Pcairo_font_face_t {.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ft_scaled_font_lock_face*(
|
||||||
|
scaled_font: Pcairo_scaled_font_t): TFT_Face{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_ft_scaled_font_unlock_face*(
|
||||||
|
scaled_font: Pcairo_scaled_font_t){.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
|
||||||
36
lib/base/cairo/cairowin32.nim
Normal file
36
lib/base/cairo/cairowin32.nim
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# Translation of cairo-win32.h version 1.4
|
||||||
|
# by Luiz Américo Pereira Câmara 2007
|
||||||
|
#
|
||||||
|
|
||||||
|
import
|
||||||
|
Cairo, windows
|
||||||
|
|
||||||
|
proc cairo_win32_surface_create*(hdc: HDC): Pcairo_surface_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_surface_create_with_ddb*(hdc: HDC, format: cairo_format_t,
|
||||||
|
width, height: int32): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_surface_create_with_dib*(format: cairo_format_t,
|
||||||
|
width, height: int32): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_surface_get_dc*(surface: pcairo_surface_t): HDC{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_surface_get_image*(surface: pcairo_surface_t): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_font_face_create_for_logfontw*(logfont: pLOGFONTW): Pcairo_font_face_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_font_face_create_for_hfont*(font: HFONT): Pcairo_font_face_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_scaled_font_select_font*(scaled_font: pcairo_scaled_font_t,
|
||||||
|
hdc: HDC): cairo_status_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_scaled_font_done_font*(scaled_font: pcairo_scaled_font_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_scaled_font_get_metrics_factor*(
|
||||||
|
scaled_font: pcairo_scaled_font_t): float64{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_scaled_font_get_logical_to_device*(
|
||||||
|
scaled_font: pcairo_scaled_font_t, logical_to_device: pcairo_matrix_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_win32_scaled_font_get_device_to_logical*(
|
||||||
|
scaled_font: pcairo_scaled_font_t, device_to_logical: pcairo_matrix_t){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
# implementation
|
||||||
40
lib/base/cairo/cairoxlib.nim
Normal file
40
lib/base/cairo/cairoxlib.nim
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# Translation of cairo-xlib.h version 1.4
|
||||||
|
# by Jeffrey Pohlmeyer
|
||||||
|
# updated to version 1.4 by Luiz Américo Pereira Câmara 2007
|
||||||
|
#
|
||||||
|
|
||||||
|
import
|
||||||
|
Cairo, x, xlib, xrender
|
||||||
|
|
||||||
|
proc cairo_xlib_surface_create*(dpy: PDisplay, drawable: TDrawable,
|
||||||
|
visual: PVisual, width, height: int32): Pcairo_surface_t{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_create_for_bitmap*(dpy: PDisplay, bitmap: TPixmap,
|
||||||
|
screen: PScreen, width, height: int32): Pcairo_surface_t{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_create_with_xrender_format*(dpy: PDisplay,
|
||||||
|
drawable: TDrawable, screen: PScreen, format: PXRenderPictFormat,
|
||||||
|
width, height: int32): Pcairo_surface_t{.cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_depth*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_display*(surface: Pcairo_surface_t): PDisplay{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_drawable*(surface: Pcairo_surface_t): TDrawable{.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_height*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_screen*(surface: Pcairo_surface_t): PScreen{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_visual*(surface: Pcairo_surface_t): PVisual{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_get_width*(surface: Pcairo_surface_t): int32{.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_set_size*(surface: Pcairo_surface_t,
|
||||||
|
width, height: int32){.cdecl, importc,
|
||||||
|
dynlib: LIB_CAIRO.}
|
||||||
|
proc cairo_xlib_surface_set_drawable*(surface: Pcairo_surface_t,
|
||||||
|
drawable: TDrawable, width, height: int32){.
|
||||||
|
cdecl, importc, dynlib: LIB_CAIRO.}
|
||||||
|
# implementation
|
||||||
234
lib/base/dialogs.nim
Executable file
234
lib/base/dialogs.nim
Executable file
|
|
@ -0,0 +1,234 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
## This module implements portable dialogs for Nimrod; the implementation
|
||||||
|
## builds on the GTK interface. On Windows, native dialogs are shown if
|
||||||
|
## appropriate.
|
||||||
|
|
||||||
|
import
|
||||||
|
glib2, gtk2
|
||||||
|
|
||||||
|
when defined(Windows):
|
||||||
|
import windows, ShellAPI, os
|
||||||
|
|
||||||
|
type
|
||||||
|
PWindow* = PGtkWindow ## A shortcut for a GTK window.
|
||||||
|
|
||||||
|
proc info*(window: PWindow, msg: string) =
|
||||||
|
## Shows an information message to the user. The process waits until the
|
||||||
|
## user presses the OK button.
|
||||||
|
when defined(Windows):
|
||||||
|
discard MessageBoxA(0, msg, "Information", MB_OK or MB_ICONINFORMATION)
|
||||||
|
else:
|
||||||
|
var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
|
||||||
|
GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", cstring(msg)))
|
||||||
|
gtk_window_set_title(dialog, "Information")
|
||||||
|
discard gtk_dialog_run(dialog)
|
||||||
|
gtk_widget_destroy(dialog)
|
||||||
|
|
||||||
|
proc warning*(window: PWindow, msg: string) =
|
||||||
|
## Shows a warning message to the user. The process waits until the user
|
||||||
|
## presses the OK button.
|
||||||
|
when defined(Windows):
|
||||||
|
discard MessageBoxA(0, msg, "Warning", MB_OK or MB_ICONWARNING)
|
||||||
|
else:
|
||||||
|
var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
|
||||||
|
GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", cstring(msg)))
|
||||||
|
gtk_window_set_title(dialog, "Warning")
|
||||||
|
discard gtk_dialog_run(dialog)
|
||||||
|
gtk_widget_destroy(dialog)
|
||||||
|
|
||||||
|
proc error*(window: PWindow, msg: string) =
|
||||||
|
## Shows an error message to the user. The process waits until the user
|
||||||
|
## presses the OK button.
|
||||||
|
when defined(Windows):
|
||||||
|
discard MessageBoxA(0, msg, "Error", MB_OK or MB_ICONERROR)
|
||||||
|
else:
|
||||||
|
var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
|
||||||
|
GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", cstring(msg)))
|
||||||
|
gtk_window_set_title(dialog, "Error")
|
||||||
|
discard gtk_dialog_run(dialog)
|
||||||
|
gtk_widget_destroy(dialog)
|
||||||
|
|
||||||
|
|
||||||
|
proc ChooseFileToOpen*(window: PWindow, root: string = ""): string =
|
||||||
|
## Opens a dialog that requests a filename from the user. Returns ""
|
||||||
|
## if the user closed the dialog without selecting a file. On Windows,
|
||||||
|
## the native dialog is used, else the GTK dialog is used.
|
||||||
|
when defined(Windows):
|
||||||
|
var
|
||||||
|
opf: TOPENFILENAME
|
||||||
|
buf: array [0..2047, char]
|
||||||
|
opf.lStructSize = sizeof(opf)
|
||||||
|
if root.len > 0:
|
||||||
|
opf.lpstrInitialDir = root
|
||||||
|
opf.lpstrFilter = "All Files\0*.*\0\0"
|
||||||
|
opf.flags = OFN_FILEMUSTEXIST
|
||||||
|
opf.lpstrFile = buf
|
||||||
|
opf.nMaxFile = sizeof(buf)
|
||||||
|
var res = GetOpenFileName(addr(opf))
|
||||||
|
if res != 0:
|
||||||
|
result = $buf
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Open File", window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
|
||||||
|
if root.len > 0:
|
||||||
|
discard gtk_file_chooser_set_current_folder(chooser, root)
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
var x = gtk_file_chooser_get_filename(chooser)
|
||||||
|
result = $x
|
||||||
|
g_free(x)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
|
proc ChooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
|
||||||
|
## Opens a dialog that requests filenames from the user. Returns []
|
||||||
|
## if the user closed the dialog without selecting a file. On Windows,
|
||||||
|
## the native dialog is used, else the GTK dialog is used.
|
||||||
|
when defined(Windows):
|
||||||
|
var
|
||||||
|
opf: TOPENFILENAME
|
||||||
|
buf: array [0..2047*4, char]
|
||||||
|
opf.lStructSize = sizeof(opf)
|
||||||
|
if root.len > 0:
|
||||||
|
opf.lpstrInitialDir = root
|
||||||
|
opf.lpstrFilter = "All Files\0*.*\0\0"
|
||||||
|
opf.flags = OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT or OFN_EXPLORER
|
||||||
|
opf.lpstrFile = buf
|
||||||
|
opf.nMaxFile = sizeof(buf)
|
||||||
|
var res = GetOpenFileName(addr(opf))
|
||||||
|
result = []
|
||||||
|
if res != 0:
|
||||||
|
# parsing the result is horrible:
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
s: string
|
||||||
|
path = ""
|
||||||
|
while buf[i] != '\0':
|
||||||
|
add(path, buf[i])
|
||||||
|
inc(i)
|
||||||
|
inc(i)
|
||||||
|
if buf[i] != '\0':
|
||||||
|
while true:
|
||||||
|
s = ""
|
||||||
|
while buf[i] != '\0':
|
||||||
|
add(s, buf[i])
|
||||||
|
inc(i)
|
||||||
|
add(result, s)
|
||||||
|
inc(i)
|
||||||
|
if buf[i] == '\0': break
|
||||||
|
for i in 0..result.len-1: result[i] = os.joinPath(path, result[i])
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Open Files", window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
|
||||||
|
if root.len > 0:
|
||||||
|
discard gtk_file_chooser_set_current_folder(chooser, root)
|
||||||
|
gtk_file_chooser_set_select_multiple(chooser, true)
|
||||||
|
result = []
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
var L = gtk_file_chooser_get_filenames(chooser)
|
||||||
|
var it = L
|
||||||
|
while it != nil:
|
||||||
|
add(result, $cast[cstring](it.data))
|
||||||
|
g_free(it.data)
|
||||||
|
it = it.next
|
||||||
|
g_slist_free(L)
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
|
|
||||||
|
proc ChooseFileToSave*(window: PWindow, root: string = ""): string =
|
||||||
|
## Opens a dialog that requests a filename to save to from the user.
|
||||||
|
## Returns "" if the user closed the dialog without selecting a file.
|
||||||
|
## On Windows, the native dialog is used, else the GTK dialog is used.
|
||||||
|
when defined(Windows):
|
||||||
|
var
|
||||||
|
opf: TOPENFILENAME
|
||||||
|
buf: array [0..2047, char]
|
||||||
|
opf.lStructSize = sizeof(opf)
|
||||||
|
if root.len > 0:
|
||||||
|
opf.lpstrInitialDir = root
|
||||||
|
opf.lpstrFilter = "All Files\0*.*\0\0"
|
||||||
|
opf.flags = OFN_OVERWRITEPROMPT
|
||||||
|
opf.lpstrFile = buf
|
||||||
|
opf.nMaxFile = sizeof(buf)
|
||||||
|
var res = GetSaveFileName(addr(opf))
|
||||||
|
if res != 0:
|
||||||
|
result = $buf
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Save File", window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
|
||||||
|
if root.len > 0:
|
||||||
|
discard gtk_file_chooser_set_current_folder(chooser, root)
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(chooser, true)
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
var x = gtk_file_chooser_get_filename(chooser)
|
||||||
|
result = $x
|
||||||
|
g_free(x)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
|
|
||||||
|
proc ChooseDir*(window: PWindow, root: string = ""): string =
|
||||||
|
## Opens a dialog that requests a directory from the user.
|
||||||
|
## Returns "" if the user closed the dialog without selecting a directory.
|
||||||
|
## On Windows, the native dialog is used, else the GTK dialog is used.
|
||||||
|
when defined(Windows):
|
||||||
|
var
|
||||||
|
lpItemID: PItemIDList
|
||||||
|
BrowseInfo: TBrowseInfo
|
||||||
|
DisplayName: array [0..MAX_PATH, char]
|
||||||
|
TempPath: array [0..MAX_PATH, char]
|
||||||
|
Result = ""
|
||||||
|
#BrowseInfo.hwndOwner = Application.Handle
|
||||||
|
BrowseInfo.pszDisplayName = DisplayName
|
||||||
|
BrowseInfo.ulFlags = 1 #BIF_RETURNONLYFSDIRS
|
||||||
|
lpItemID = SHBrowseForFolder(cast[LPBrowseInfo](addr(BrowseInfo)))
|
||||||
|
if lpItemId != nil:
|
||||||
|
discard SHGetPathFromIDList(lpItemID, TempPath)
|
||||||
|
Result = $TempPath
|
||||||
|
discard GlobalFreePtr(lpItemID)
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
chooser: PGtkDialog
|
||||||
|
chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Select Directory", window,
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
|
||||||
|
if root.len > 0:
|
||||||
|
discard gtk_file_chooser_set_current_folder(chooser, root)
|
||||||
|
if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
|
||||||
|
var x = gtk_file_chooser_get_filename(chooser)
|
||||||
|
result = $x
|
||||||
|
g_free(x)
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
gtk_widget_destroy(chooser)
|
||||||
|
|
||||||
1368
lib/base/gtk/atk.nim
Executable file
1368
lib/base/gtk/atk.nim
Executable file
File diff suppressed because it is too large
Load diff
3957
lib/base/gtk/gdk2.nim
Executable file
3957
lib/base/gtk/gdk2.nim
Executable file
File diff suppressed because it is too large
Load diff
279
lib/base/gtk/gdk2pixbuf.nim
Executable file
279
lib/base/gtk/gdk2pixbuf.nim
Executable file
|
|
@ -0,0 +1,279 @@
|
||||||
|
import
|
||||||
|
glib2
|
||||||
|
|
||||||
|
when defined(win32):
|
||||||
|
{.define: gdkpixbufwin.}
|
||||||
|
const
|
||||||
|
gdkpixbuflib = "libgdk_pixbuf-2.0-0.dll"
|
||||||
|
elif defined(darwin):
|
||||||
|
const
|
||||||
|
gdkpixbuflib = "gdk_pixbuf-2.0.0"
|
||||||
|
# linklib gtk-x11-2.0
|
||||||
|
# linklib gdk-x11-2.0
|
||||||
|
# linklib pango-1.0.0
|
||||||
|
# linklib glib-2.0.0
|
||||||
|
# linklib gobject-2.0.0
|
||||||
|
# linklib gdk_pixbuf-2.0.0
|
||||||
|
# linklib atk-1.0.0
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
gdkpixbuflib = "libgdk_pixbuf-2.0.so"
|
||||||
|
{.define: HasGTK2_4.}
|
||||||
|
{.define: HasGTK2_6.}
|
||||||
|
type
|
||||||
|
PGdkPixbuf* = pointer
|
||||||
|
PGdkPixbufAnimation* = pointer
|
||||||
|
PGdkPixbufAnimationIter* = pointer
|
||||||
|
PGdkPixbufAlphaMode* = ptr TGdkPixbufAlphaMode
|
||||||
|
TGdkPixbufAlphaMode* = enum
|
||||||
|
GDK_PIXBUF_ALPHA_BILEVEL, GDK_PIXBUF_ALPHA_FULL
|
||||||
|
PGdkColorspace* = ptr TGdkColorspace
|
||||||
|
TGdkColorspace* = enum
|
||||||
|
GDK_COLORSPACE_RGB
|
||||||
|
TGdkPixbufDestroyNotify* = proc (pixels: Pguchar, data: gpointer){.cdecl.}
|
||||||
|
PGdkPixbufError* = ptr TGdkPixbufError
|
||||||
|
TGdkPixbufError* = enum
|
||||||
|
GDK_PIXBUF_ERROR_CORRUPT_IMAGE, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
|
GDK_PIXBUF_ERROR_BAD_OPTION, GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
||||||
|
GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION, GDK_PIXBUF_ERROR_FAILED
|
||||||
|
PGdkInterpType* = ptr TGdkInterpType
|
||||||
|
TGdkInterpType* = enum
|
||||||
|
GDK_INTERP_NEAREST, GDK_INTERP_TILES, GDK_INTERP_BILINEAR, GDK_INTERP_HYPER
|
||||||
|
|
||||||
|
proc GDK_TYPE_PIXBUF*(): GType
|
||||||
|
proc GDK_PIXBUF*(anObject: pointer): PGdkPixbuf
|
||||||
|
proc GDK_IS_PIXBUF*(anObject: pointer): bool
|
||||||
|
proc GDK_TYPE_PIXBUF_ANIMATION*(): GType
|
||||||
|
proc GDK_PIXBUF_ANIMATION*(anObject: pointer): PGdkPixbufAnimation
|
||||||
|
proc GDK_IS_PIXBUF_ANIMATION*(anObject: pointer): bool
|
||||||
|
proc GDK_TYPE_PIXBUF_ANIMATION_ITER*(): GType
|
||||||
|
proc GDK_PIXBUF_ANIMATION_ITER*(anObject: pointer): PGdkPixbufAnimationIter
|
||||||
|
proc GDK_IS_PIXBUF_ANIMATION_ITER*(anObject: pointer): bool
|
||||||
|
proc GDK_PIXBUF_ERROR*(): TGQuark
|
||||||
|
proc gdk_pixbuf_error_quark*(): TGQuark{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_error_quark".}
|
||||||
|
proc gdk_pixbuf_get_type*(): GType{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_get_type".}
|
||||||
|
when not defined(GDK_PIXBUF_DISABLE_DEPRECATED):
|
||||||
|
proc gdk_pixbuf_ref(pixbuf: PGdkPixbuf): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_ref".}
|
||||||
|
proc gdk_pixbuf_unref(pixbuf: PGdkPixbuf){.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_unref".}
|
||||||
|
proc gdk_pixbuf_get_colorspace*(pixbuf: PGdkPixbuf): TGdkColorspace{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_colorspace".}
|
||||||
|
proc gdk_pixbuf_get_n_channels*(pixbuf: PGdkPixbuf): int32{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_n_channels".}
|
||||||
|
proc gdk_pixbuf_get_has_alpha*(pixbuf: PGdkPixbuf): gboolean{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_has_alpha".}
|
||||||
|
proc gdk_pixbuf_get_bits_per_sample*(pixbuf: PGdkPixbuf): int32{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_bits_per_sample".}
|
||||||
|
proc gdk_pixbuf_get_pixels*(pixbuf: PGdkPixbuf): Pguchar{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_pixels".}
|
||||||
|
proc gdk_pixbuf_get_width*(pixbuf: PGdkPixbuf): int32{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_width".}
|
||||||
|
proc gdk_pixbuf_get_height*(pixbuf: PGdkPixbuf): int32{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_height".}
|
||||||
|
proc gdk_pixbuf_get_rowstride*(pixbuf: PGdkPixbuf): int32{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_rowstride".}
|
||||||
|
proc gdk_pixbuf_new*(colorspace: TGdkColorspace, has_alpha: gboolean,
|
||||||
|
bits_per_sample: int32, width: int32, height: int32): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new".}
|
||||||
|
proc gdk_pixbuf_copy*(pixbuf: PGdkPixbuf): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_copy".}
|
||||||
|
proc gdk_pixbuf_new_subpixbuf*(src_pixbuf: PGdkPixbuf, src_x: int32,
|
||||||
|
src_y: int32, width: int32, height: int32): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_subpixbuf".}
|
||||||
|
proc gdk_pixbuf_new_from_file*(filename: cstring, error: pointer): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_file".}
|
||||||
|
proc gdk_pixbuf_new_from_data*(data: Pguchar, colorspace: TGdkColorspace,
|
||||||
|
has_alpha: gboolean, bits_per_sample: int32,
|
||||||
|
width: int32, height: int32, rowstride: int32,
|
||||||
|
destroy_fn: TGdkPixbufDestroyNotify,
|
||||||
|
destroy_fn_data: gpointer): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_data".}
|
||||||
|
proc gdk_pixbuf_new_from_xpm_data*(data: PPchar): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_xpm_data".}
|
||||||
|
proc gdk_pixbuf_new_from_inline*(data_length: gint, a: var guint8,
|
||||||
|
copy_pixels: gboolean, error: pointer): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_inline".}
|
||||||
|
when defined(HasGTK2_4):
|
||||||
|
proc gdk_pixbuf_new_from_file_at_size(filename: cstring, width, height: gint,
|
||||||
|
error: pointer): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_file_at_size".}
|
||||||
|
when defined(HasGTK2_6):
|
||||||
|
proc gdk_pixbuf_new_from_file_at_scale(filename: cstring, width, height: gint,
|
||||||
|
preserve_aspect_ratio: gboolean, error: pointer): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_new_from_file_at_scale".}
|
||||||
|
proc gdk_pixbuf_fill*(pixbuf: PGdkPixbuf, pixel: guint32){.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_fill".}
|
||||||
|
proc gdk_pixbuf_save*(pixbuf: PGdkPixbuf, filename: cstring, `type`: cstring,
|
||||||
|
error: pointer): gboolean{.cdecl, varargs,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_save".}
|
||||||
|
proc gdk_pixbuf_savev*(pixbuf: PGdkPixbuf, filename: cstring, `type`: cstring,
|
||||||
|
option_keys: PPchar, option_values: PPchar,
|
||||||
|
error: pointer): gboolean{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_savev".}
|
||||||
|
proc gdk_pixbuf_add_alpha*(pixbuf: PGdkPixbuf, substitute_color: gboolean,
|
||||||
|
r: guchar, g: guchar, b: guchar): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_add_alpha".}
|
||||||
|
proc gdk_pixbuf_copy_area*(src_pixbuf: PGdkPixbuf, src_x: int32, src_y: int32,
|
||||||
|
width: int32, height: int32, dest_pixbuf: PGdkPixbuf,
|
||||||
|
dest_x: int32, dest_y: int32){.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_copy_area".}
|
||||||
|
proc gdk_pixbuf_saturate_and_pixelate*(src: PGdkPixbuf, dest: PGdkPixbuf,
|
||||||
|
saturation: gfloat, pixelate: gboolean){.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_saturate_and_pixelate".}
|
||||||
|
proc gdk_pixbuf_scale*(src: PGdkPixbuf, dest: PGdkPixbuf, dest_x: int32,
|
||||||
|
dest_y: int32, dest_width: int32, dest_height: int32,
|
||||||
|
offset_x: float64, offset_y: float64, scale_x: float64,
|
||||||
|
scale_y: float64, interp_type: TGdkInterpType){.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_scale".}
|
||||||
|
proc gdk_pixbuf_composite*(src: PGdkPixbuf, dest: PGdkPixbuf, dest_x: int32,
|
||||||
|
dest_y: int32, dest_width: int32, dest_height: int32,
|
||||||
|
offset_x: float64, offset_y: float64,
|
||||||
|
scale_x: float64, scale_y: float64,
|
||||||
|
interp_type: TGdkInterpType, overall_alpha: int32){.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_composite".}
|
||||||
|
proc gdk_pixbuf_composite_color*(src: PGdkPixbuf, dest: PGdkPixbuf,
|
||||||
|
dest_x: int32, dest_y: int32,
|
||||||
|
dest_width: int32, dest_height: int32,
|
||||||
|
offset_x: float64, offset_y: float64,
|
||||||
|
scale_x: float64, scale_y: float64,
|
||||||
|
interp_type: TGdkInterpType,
|
||||||
|
overall_alpha: int32, check_x: int32,
|
||||||
|
check_y: int32, check_size: int32,
|
||||||
|
color1: guint32, color2: guint32){.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_composite_color".}
|
||||||
|
proc gdk_pixbuf_scale_simple*(src: PGdkPixbuf, dest_width: int32,
|
||||||
|
dest_height: int32, interp_type: TGdkInterpType): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_scale_simple".}
|
||||||
|
proc gdk_pixbuf_composite_color_simple*(src: PGdkPixbuf, dest_width: int32,
|
||||||
|
dest_height: int32,
|
||||||
|
interp_type: TGdkInterpType,
|
||||||
|
overall_alpha: int32, check_size: int32,
|
||||||
|
color1: guint32, color2: guint32): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_composite_color_simple".}
|
||||||
|
proc gdk_pixbuf_animation_get_type*(): GType{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_animation_get_type".}
|
||||||
|
proc gdk_pixbuf_animation_new_from_file*(filename: cstring, error: pointer): PGdkPixbufAnimation{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_new_from_file".}
|
||||||
|
when not defined(GDK_PIXBUF_DISABLE_DEPRECATED):
|
||||||
|
proc gdk_pixbuf_animation_ref(animation: PGdkPixbufAnimation): PGdkPixbufAnimation{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_ref".}
|
||||||
|
proc gdk_pixbuf_animation_unref(animation: PGdkPixbufAnimation){.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_unref".}
|
||||||
|
proc gdk_pixbuf_animation_get_width*(animation: PGdkPixbufAnimation): int32{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_get_width".}
|
||||||
|
proc gdk_pixbuf_animation_get_height*(animation: PGdkPixbufAnimation): int32{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_get_height".}
|
||||||
|
proc gdk_pixbuf_animation_is_static_image*(animation: PGdkPixbufAnimation): gboolean{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_is_static_image".}
|
||||||
|
proc gdk_pixbuf_animation_get_static_image*(animation: PGdkPixbufAnimation): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_animation_get_static_image".}
|
||||||
|
proc gdk_pixbuf_animation_get_iter*(animation: PGdkPixbufAnimation,
|
||||||
|
e: var TGTimeVal): PGdkPixbufAnimationIter{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_get_iter".}
|
||||||
|
proc gdk_pixbuf_animation_iter_get_type*(): GType{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_animation_iter_get_type".}
|
||||||
|
proc gdk_pixbuf_animation_iter_get_delay_time*(iter: PGdkPixbufAnimationIter): int32{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_animation_iter_get_delay_time".}
|
||||||
|
proc gdk_pixbuf_animation_iter_get_pixbuf*(iter: PGdkPixbufAnimationIter): PGdkPixbuf{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_iter_get_pixbuf".}
|
||||||
|
proc gdk_pixbuf_animation_iter_on_currently_loading_frame*(
|
||||||
|
iter: PGdkPixbufAnimationIter): gboolean{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_animation_iter_on_currently_loading_frame".}
|
||||||
|
proc gdk_pixbuf_animation_iter_advance*(iter: PGdkPixbufAnimationIter,
|
||||||
|
e: var TGTimeVal): gboolean{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_animation_iter_advance".}
|
||||||
|
proc gdk_pixbuf_get_option*(pixbuf: PGdkPixbuf, key: cstring): cstring{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_option".}
|
||||||
|
type
|
||||||
|
PGdkPixbufLoader* = ptr TGdkPixbufLoader
|
||||||
|
TGdkPixbufLoader* = record
|
||||||
|
parent_instance*: TGObject
|
||||||
|
priv*: gpointer
|
||||||
|
|
||||||
|
PGdkPixbufLoaderClass* = ptr TGdkPixbufLoaderClass
|
||||||
|
TGdkPixbufLoaderClass* = record
|
||||||
|
parent_class*: TGObjectClass
|
||||||
|
area_prepared*: proc (loader: PGdkPixbufLoader){.cdecl.}
|
||||||
|
area_updated*: proc (loader: PGdkPixbufLoader, x: int32, y: int32,
|
||||||
|
width: int32, height: int32){.cdecl.}
|
||||||
|
closed*: proc (loader: PGdkPixbufLoader){.cdecl.}
|
||||||
|
|
||||||
|
|
||||||
|
proc GDK_TYPE_PIXBUF_LOADER*(): GType
|
||||||
|
proc GDK_PIXBUF_LOADER*(obj: pointer): PGdkPixbufLoader
|
||||||
|
proc GDK_PIXBUF_LOADER_CLASS*(klass: pointer): PGdkPixbufLoaderClass
|
||||||
|
proc GDK_IS_PIXBUF_LOADER*(obj: pointer): bool
|
||||||
|
proc GDK_IS_PIXBUF_LOADER_CLASS*(klass: pointer): bool
|
||||||
|
proc GDK_PIXBUF_LOADER_GET_CLASS*(obj: pointer): PGdkPixbufLoaderClass
|
||||||
|
proc gdk_pixbuf_loader_get_type*(): GType{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_loader_get_type".}
|
||||||
|
proc gdk_pixbuf_loader_new*(): PGdkPixbufLoader{.cdecl, dynlib: gdkpixbuflib,
|
||||||
|
importc: "gdk_pixbuf_loader_new".}
|
||||||
|
proc gdk_pixbuf_loader_new_with_type*(image_type: cstring, error: pointer): PGdkPixbufLoader{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_loader_new_with_type".}
|
||||||
|
proc gdk_pixbuf_loader_write*(loader: PGdkPixbufLoader, buf: Pguchar,
|
||||||
|
count: gsize, error: pointer): gboolean{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_loader_write".}
|
||||||
|
proc gdk_pixbuf_loader_get_pixbuf*(loader: PGdkPixbufLoader): PGdkPixbuf{.cdecl,
|
||||||
|
dynlib: gdkpixbuflib, importc: "gdk_pixbuf_loader_get_pixbuf".}
|
||||||
|
proc gdk_pixbuf_loader_get_animation*(loader: PGdkPixbufLoader): PGdkPixbufAnimation{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_loader_get_animation".}
|
||||||
|
proc gdk_pixbuf_loader_close*(loader: PGdkPixbufLoader, error: pointer): gboolean{.
|
||||||
|
cdecl, dynlib: gdkpixbuflib, importc: "gdk_pixbuf_loader_close".}
|
||||||
|
proc GDK_TYPE_PIXBUF_LOADER*(): GType =
|
||||||
|
result = gdk_pixbuf_loader_get_type()
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_LOADER*(obj: pointer): PGdkPixbufLoader =
|
||||||
|
result = cast[PGdkPixbufLoader](G_TYPE_CHECK_INSTANCE_CAST(obj,
|
||||||
|
GDK_TYPE_PIXBUF_LOADER()))
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_LOADER_CLASS*(klass: pointer): PGdkPixbufLoaderClass =
|
||||||
|
result = cast[PGdkPixbufLoaderClass](G_TYPE_CHECK_CLASS_CAST(klass,
|
||||||
|
GDK_TYPE_PIXBUF_LOADER()))
|
||||||
|
|
||||||
|
proc GDK_IS_PIXBUF_LOADER*(obj: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(obj, GDK_TYPE_PIXBUF_LOADER())
|
||||||
|
|
||||||
|
proc GDK_IS_PIXBUF_LOADER_CLASS*(klass: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GDK_TYPE_PIXBUF_LOADER())
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_LOADER_GET_CLASS*(obj: pointer): PGdkPixbufLoaderClass =
|
||||||
|
result = cast[PGdkPixbufLoaderClass](G_TYPE_INSTANCE_GET_CLASS(obj,
|
||||||
|
GDK_TYPE_PIXBUF_LOADER()))
|
||||||
|
|
||||||
|
proc GDK_TYPE_PIXBUF*(): GType =
|
||||||
|
result = gdk_pixbuf_get_type()
|
||||||
|
|
||||||
|
proc GDK_PIXBUF*(anObject: pointer): PGdkPixbuf =
|
||||||
|
result = cast[PGdkPixbuf](G_TYPE_CHECK_INSTANCE_CAST(anObject, GDK_TYPE_PIXBUF()))
|
||||||
|
|
||||||
|
proc GDK_IS_PIXBUF*(anObject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_PIXBUF())
|
||||||
|
|
||||||
|
proc GDK_TYPE_PIXBUF_ANIMATION*(): GType =
|
||||||
|
result = gdk_pixbuf_animation_get_type()
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_ANIMATION*(anObject: pointer): PGdkPixbufAnimation =
|
||||||
|
result = cast[PGdkPixbufAnimation](G_TYPE_CHECK_INSTANCE_CAST(anObject,
|
||||||
|
GDK_TYPE_PIXBUF_ANIMATION()))
|
||||||
|
|
||||||
|
proc GDK_IS_PIXBUF_ANIMATION*(anObject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_PIXBUF_ANIMATION())
|
||||||
|
|
||||||
|
proc GDK_TYPE_PIXBUF_ANIMATION_ITER*(): GType =
|
||||||
|
result = gdk_pixbuf_animation_iter_get_type()
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_ANIMATION_ITER*(anObject: pointer): PGdkPixbufAnimationIter =
|
||||||
|
result = cast[PGdkPixbufAnimationIter](G_TYPE_CHECK_INSTANCE_CAST(anObject,
|
||||||
|
GDK_TYPE_PIXBUF_ANIMATION_ITER()))
|
||||||
|
|
||||||
|
proc GDK_IS_PIXBUF_ANIMATION_ITER*(anObject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_PIXBUF_ANIMATION_ITER())
|
||||||
|
|
||||||
|
proc GDK_PIXBUF_ERROR*(): TGQuark =
|
||||||
|
result = gdk_pixbuf_error_quark()
|
||||||
562
lib/base/gtk/gdkglext.nim
Executable file
562
lib/base/gtk/gdkglext.nim
Executable file
|
|
@ -0,0 +1,562 @@
|
||||||
|
import
|
||||||
|
Glib2, Gdk2
|
||||||
|
|
||||||
|
when defined(WIN32):
|
||||||
|
const
|
||||||
|
GdkGLExtLib = "libgdkglext-win32-1.0-0.dll"
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
GdkGLExtLib = "libgdkglext-x11-1.0.so"
|
||||||
|
type
|
||||||
|
TGdkGLConfigAttrib* = int32
|
||||||
|
TGdkGLConfigCaveat* = int32
|
||||||
|
TGdkGLVisualType* = int32
|
||||||
|
TGdkGLTransparentType* = int32
|
||||||
|
TGdkGLDrawableTypeMask* = int32
|
||||||
|
TGdkGLRenderTypeMask* = int32
|
||||||
|
TGdkGLBufferMask* = int32
|
||||||
|
TGdkGLConfigError* = int32
|
||||||
|
TGdkGLRenderType* = int32
|
||||||
|
TGdkGLDrawableAttrib* = int32
|
||||||
|
TGdkGLPbufferAttrib* = int32
|
||||||
|
TGdkGLEventMask* = int32
|
||||||
|
TGdkGLEventType* = int32
|
||||||
|
TGdkGLDrawableType* = int32
|
||||||
|
TGdkGLProc* = Pointer
|
||||||
|
PGdkGLConfig* = ptr TGdkGLConfig
|
||||||
|
PGdkGLContext* = ptr TGdkGLContext
|
||||||
|
PGdkGLDrawable* = ptr TGdkGLDrawable
|
||||||
|
PGdkGLPixmap* = ptr TGdkGLPixmap
|
||||||
|
PGdkGLWindow* = ptr TGdkGLWindow
|
||||||
|
TGdkGLConfig* = object of TGObject
|
||||||
|
layer_plane*: gint
|
||||||
|
n_aux_buffers*: gint
|
||||||
|
n_sample_buffers*: gint
|
||||||
|
flag0*: int16
|
||||||
|
|
||||||
|
PGdkGLConfigClass* = ptr TGdkGLConfigClass
|
||||||
|
TGdkGLConfigClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
TGdkGLContext* = object of TGObject
|
||||||
|
|
||||||
|
PGdkGLContextClass* = ptr TGdkGLContextClass
|
||||||
|
TGdkGLContextClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
TGdkGLDrawable* = object of TGObject
|
||||||
|
|
||||||
|
PGdkGLDrawableClass* = ptr TGdkGLDrawableClass
|
||||||
|
TGdkGLDrawableClass* = object of TGTypeInterface
|
||||||
|
create_new_context*: proc (gldrawable: PGdkGLDrawable,
|
||||||
|
share_list: PGdkGLContext, direct: gboolean,
|
||||||
|
render_type: int32): PGdkGLContext{.cdecl.}
|
||||||
|
make_context_current*: proc (draw: PGdkGLDrawable, a_read: PGdkGLDrawable,
|
||||||
|
glcontext: PGdkGLContext): gboolean{.cdecl.}
|
||||||
|
is_double_buffered*: proc (gldrawable: PGdkGLDrawable): gboolean{.cdecl.}
|
||||||
|
swap_buffers*: proc (gldrawable: PGdkGLDrawable){.cdecl.}
|
||||||
|
wait_gl*: proc (gldrawable: PGdkGLDrawable){.cdecl.}
|
||||||
|
wait_gdk*: proc (gldrawable: PGdkGLDrawable){.cdecl.}
|
||||||
|
gl_begin*: proc (draw: PGdkGLDrawable, a_read: PGdkGLDrawable,
|
||||||
|
glcontext: PGdkGLContext): gboolean{.cdecl.}
|
||||||
|
gl_end*: proc (gldrawable: PGdkGLDrawable){.cdecl.}
|
||||||
|
get_gl_config*: proc (gldrawable: PGdkGLDrawable): PGdkGLConfig{.cdecl.}
|
||||||
|
get_size*: proc (gldrawable: PGdkGLDrawable, width, height: PGInt){.cdecl.}
|
||||||
|
|
||||||
|
TGdkGLPixmap* = object of TGObject
|
||||||
|
drawable*: PGdkDrawable
|
||||||
|
|
||||||
|
PGdkGLPixmapClass* = ptr TGdkGLPixmapClass
|
||||||
|
TGdkGLPixmapClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
TGdkGLWindow* = object of TGObject
|
||||||
|
drawable*: PGdkDrawable
|
||||||
|
|
||||||
|
PGdkGLWindowClass* = ptr TGdkGLWindowClass
|
||||||
|
TGdkGLWindowClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
HEADER_GDKGLEXT_MAJOR_VERSION* = 1
|
||||||
|
HEADER_GDKGLEXT_MINOR_VERSION* = 0
|
||||||
|
HEADER_GDKGLEXT_MICRO_VERSION* = 6
|
||||||
|
HEADER_GDKGLEXT_INTERFACE_AGE* = 4
|
||||||
|
HEADER_GDKGLEXT_BINARY_AGE* = 6
|
||||||
|
|
||||||
|
proc HEADER_GDKGLEXT_CHECK_VERSION*(major, minor, micro: guint): bool
|
||||||
|
var
|
||||||
|
gdkglext_major_version*{.importc, dynlib: GdkGLExtLib.}: guint
|
||||||
|
gdkglext_minor_version*{.importc, dynlib: GdkGLExtLib.}: guint
|
||||||
|
gdkglext_micro_version*{.importc, dynlib: GdkGLExtLib.}: guint
|
||||||
|
gdkglext_interface_age*{.importc, dynlib: GdkGLExtLib.}: guint
|
||||||
|
gdkglext_binary_age*{.importc, dynlib: GdkGLExtLib.}: guint
|
||||||
|
|
||||||
|
const
|
||||||
|
GDK_GL_SUCCESS* = 0
|
||||||
|
GDK_GL_ATTRIB_LIST_NONE* = 0
|
||||||
|
GDK_GL_USE_GL* = 1
|
||||||
|
GDK_GL_BUFFER_SIZE* = 2
|
||||||
|
GDK_GL_LEVEL* = 3
|
||||||
|
GDK_GL_RGBA* = 4
|
||||||
|
GDK_GL_DOUBLEBUFFER* = 5
|
||||||
|
GDK_GL_STEREO* = 6
|
||||||
|
GDK_GL_AUX_BUFFERS* = 7
|
||||||
|
GDK_GL_RED_SIZE* = 8
|
||||||
|
GDK_GL_GREEN_SIZE* = 9
|
||||||
|
GDK_GL_BLUE_SIZE* = 10
|
||||||
|
GDK_GL_ALPHA_SIZE* = 11
|
||||||
|
GDK_GL_DEPTH_SIZE* = 12
|
||||||
|
GDK_GL_STENCIL_SIZE* = 13
|
||||||
|
GDK_GL_ACCUM_RED_SIZE* = 14
|
||||||
|
GDK_GL_ACCUM_GREEN_SIZE* = 15
|
||||||
|
GDK_GL_ACCUM_BLUE_SIZE* = 16
|
||||||
|
GDK_GL_ACCUM_ALPHA_SIZE* = 17
|
||||||
|
GDK_GL_CONFIG_CAVEAT* = 0x00000020
|
||||||
|
GDK_GL_X_VISUAL_TYPE* = 0x00000022
|
||||||
|
GDK_GL_TRANSPARENT_TYPE* = 0x00000023
|
||||||
|
GDK_GL_TRANSPARENT_INDEX_VALUE* = 0x00000024
|
||||||
|
GDK_GL_TRANSPARENT_RED_VALUE* = 0x00000025
|
||||||
|
GDK_GL_TRANSPARENT_GREEN_VALUE* = 0x00000026
|
||||||
|
GDK_GL_TRANSPARENT_BLUE_VALUE* = 0x00000027
|
||||||
|
GDK_GL_TRANSPARENT_ALPHA_VALUE* = 0x00000028
|
||||||
|
GDK_GL_DRAWABLE_TYPE* = 0x00008010
|
||||||
|
GDK_GL_RENDER_TYPE* = 0x00008011
|
||||||
|
GDK_GL_X_RENDERABLE* = 0x00008012
|
||||||
|
GDK_GL_FBCONFIG_ID* = 0x00008013
|
||||||
|
GDK_GL_MAX_PBUFFER_WIDTH* = 0x00008016
|
||||||
|
GDK_GL_MAX_PBUFFER_HEIGHT* = 0x00008017
|
||||||
|
GDK_GL_MAX_PBUFFER_PIXELS* = 0x00008018
|
||||||
|
GDK_GL_VISUAL_ID* = 0x0000800B
|
||||||
|
GDK_GL_SCREEN* = 0x0000800C
|
||||||
|
GDK_GL_SAMPLE_BUFFERS* = 100000
|
||||||
|
GDK_GL_SAMPLES* = 100001
|
||||||
|
GDK_GL_DONT_CARE* = 0xFFFFFFFF
|
||||||
|
GDK_GL_NONE* = 0x00008000
|
||||||
|
GDK_GL_CONFIG_CAVEAT_DONT_CARE* = 0xFFFFFFFF
|
||||||
|
GDK_GL_CONFIG_CAVEAT_NONE* = 0x00008000
|
||||||
|
GDK_GL_SLOW_CONFIG* = 0x00008001
|
||||||
|
GDK_GL_NON_CONFORMANT_CONFIG* = 0x0000800D
|
||||||
|
GDK_GL_VISUAL_TYPE_DONT_CARE* = 0xFFFFFFFF
|
||||||
|
GDK_GL_TRUE_COLOR* = 0x00008002
|
||||||
|
GDK_GL_DIRECT_COLOR* = 0x00008003
|
||||||
|
GDK_GL_PSEUDO_COLOR* = 0x00008004
|
||||||
|
GDK_GL_STATIC_COLOR* = 0x00008005
|
||||||
|
GDK_GL_GRAY_SCALE* = 0x00008006
|
||||||
|
GDK_GL_STATIC_GRAY* = 0x00008007
|
||||||
|
GDK_GL_TRANSPARENT_NONE* = 0x00008000
|
||||||
|
GDK_GL_TRANSPARENT_RGB* = 0x00008008
|
||||||
|
GDK_GL_TRANSPARENT_INDEX* = 0x00008009
|
||||||
|
GDK_GL_WINDOW_BIT* = 1 shl 0
|
||||||
|
GDK_GL_PIXMAP_BIT* = 1 shl 1
|
||||||
|
GDK_GL_PBUFFER_BIT* = 1 shl 2
|
||||||
|
GDK_GL_RGBA_BIT* = 1 shl 0
|
||||||
|
GDK_GL_COLOR_INDEX_BIT* = 1 shl 1
|
||||||
|
GDK_GL_FRONT_LEFT_BUFFER_BIT* = 1 shl 0
|
||||||
|
GDK_GL_FRONT_RIGHT_BUFFER_BIT* = 1 shl 1
|
||||||
|
GDK_GL_BACK_LEFT_BUFFER_BIT* = 1 shl 2
|
||||||
|
GDK_GL_BACK_RIGHT_BUFFER_BIT* = 1 shl 3
|
||||||
|
GDK_GL_AUX_BUFFERS_BIT* = 1 shl 4
|
||||||
|
GDK_GL_DEPTH_BUFFER_BIT* = 1 shl 5
|
||||||
|
GDK_GL_STENCIL_BUFFER_BIT* = 1 shl 6
|
||||||
|
GDK_GL_ACCUM_BUFFER_BIT* = 1 shl 7
|
||||||
|
GDK_GL_BAD_SCREEN* = 1
|
||||||
|
GDK_GL_BAD_ATTRIBUTE* = 2
|
||||||
|
GDK_GL_NO_EXTENSION* = 3
|
||||||
|
GDK_GL_BAD_VISUAL* = 4
|
||||||
|
GDK_GL_BAD_CONTEXT* = 5
|
||||||
|
GDK_GL_BAD_VALUE* = 6
|
||||||
|
GDK_GL_BAD_ENUM* = 7
|
||||||
|
GDK_GL_RGBA_TYPE* = 0x00008014
|
||||||
|
GDK_GL_COLOR_INDEX_TYPE* = 0x00008015
|
||||||
|
GDK_GL_PRESERVED_CONTENTS* = 0x0000801B
|
||||||
|
GDK_GL_LARGEST_PBUFFER* = 0x0000801C
|
||||||
|
GDK_GL_WIDTH* = 0x0000801D
|
||||||
|
GDK_GL_HEIGHT* = 0x0000801E
|
||||||
|
GDK_GL_EVENT_MASK* = 0x0000801F
|
||||||
|
GDK_GL_PBUFFER_PRESERVED_CONTENTS* = 0x0000801B
|
||||||
|
GDK_GL_PBUFFER_LARGEST_PBUFFER* = 0x0000801C
|
||||||
|
GDK_GL_PBUFFER_HEIGHT* = 0x00008040
|
||||||
|
GDK_GL_PBUFFER_WIDTH* = 0x00008041
|
||||||
|
GDK_GL_PBUFFER_CLOBBER_MASK* = 1 shl 27
|
||||||
|
GDK_GL_DAMAGED* = 0x00008020
|
||||||
|
GDK_GL_SAVED* = 0x00008021
|
||||||
|
GDK_GL_WINDOW_VALUE* = 0x00008022
|
||||||
|
GDK_GL_PBUFFER* = 0x00008023
|
||||||
|
|
||||||
|
proc gdk_gl_config_attrib_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_attrib_get_type".}
|
||||||
|
proc GDK_TYPE_GL_CONFIG_ATTRIB*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_attrib_get_type".}
|
||||||
|
proc gdk_gl_config_caveat_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_caveat_get_type".}
|
||||||
|
proc GDK_TYPE_GL_CONFIG_CAVEAT*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_caveat_get_type".}
|
||||||
|
proc gdk_gl_visual_type_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_visual_type_get_type".}
|
||||||
|
proc GDK_TYPE_GL_VISUAL_TYPE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_visual_type_get_type".}
|
||||||
|
proc gdk_gl_transparent_type_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_transparent_type_get_type".}
|
||||||
|
proc GDK_TYPE_GL_TRANSPARENT_TYPE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_transparent_type_get_type".}
|
||||||
|
proc gdk_gl_drawable_type_mask_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_type_mask_get_type".}
|
||||||
|
proc GDK_TYPE_GL_DRAWABLE_TYPE_MASK*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_type_mask_get_type".}
|
||||||
|
proc gdk_gl_render_type_mask_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_render_type_mask_get_type".}
|
||||||
|
proc GDK_TYPE_GL_RENDER_TYPE_MASK*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_render_type_mask_get_type".}
|
||||||
|
proc gdk_gl_buffer_mask_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_buffer_mask_get_type".}
|
||||||
|
proc GDK_TYPE_GL_BUFFER_MASK*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_buffer_mask_get_type".}
|
||||||
|
proc gdk_gl_config_error_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_error_get_type".}
|
||||||
|
proc GDK_TYPE_GL_CONFIG_ERROR*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_error_get_type".}
|
||||||
|
proc gdk_gl_render_type_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_render_type_get_type".}
|
||||||
|
proc GDK_TYPE_GL_RENDER_TYPE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_render_type_get_type".}
|
||||||
|
proc gdk_gl_drawable_attrib_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_attrib_get_type".}
|
||||||
|
proc GDK_TYPE_GL_DRAWABLE_ATTRIB*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_attrib_get_type".}
|
||||||
|
proc gdk_gl_pbuffer_attrib_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_pbuffer_attrib_get_type".}
|
||||||
|
proc GDK_TYPE_GL_PBUFFER_ATTRIB*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_pbuffer_attrib_get_type".}
|
||||||
|
proc gdk_gl_event_mask_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_event_mask_get_type".}
|
||||||
|
proc GDK_TYPE_GL_EVENT_MASK*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_event_mask_get_type".}
|
||||||
|
proc gdk_gl_event_type_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_event_type_get_type".}
|
||||||
|
proc GDK_TYPE_GL_EVENT_TYPE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_event_type_get_type".}
|
||||||
|
proc gdk_gl_drawable_type_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_type_get_type".}
|
||||||
|
proc GDK_TYPE_GL_DRAWABLE_TYPE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_type_get_type".}
|
||||||
|
proc gdk_gl_config_mode_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_mode_get_type".}
|
||||||
|
proc GDK_TYPE_GL_CONFIG_MODE*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_mode_get_type".}
|
||||||
|
proc gdk_gl_parse_args*(argc: var int32, argv: ptr cstringArray): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_parse_args".}
|
||||||
|
proc gdk_gl_init_check*(argc: var int32, argv: ptr cstringArray): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_init_check".}
|
||||||
|
proc gdk_gl_init*(argc: var int32, argv: ptr cstringArray){.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_init".}
|
||||||
|
proc gdk_gl_query_gl_extension*(extension: cstring): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_query_gl_extension".}
|
||||||
|
proc gdk_gl_get_proc_address*(proc_name: cstring): TGdkGLProc{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_get_proc_address".}
|
||||||
|
const
|
||||||
|
bm_TGdkGLConfig_is_rgba* = 1 shl 0
|
||||||
|
bp_TGdkGLConfig_is_rgba* = 0
|
||||||
|
bm_TGdkGLConfig_is_double_buffered* = 1 shl 1
|
||||||
|
bp_TGdkGLConfig_is_double_buffered* = 1
|
||||||
|
bm_TGdkGLConfig_as_single_mode* = 1 shl 2
|
||||||
|
bp_TGdkGLConfig_as_single_mode* = 2
|
||||||
|
bm_TGdkGLConfig_is_stereo* = 1 shl 3
|
||||||
|
bp_TGdkGLConfig_is_stereo* = 3
|
||||||
|
bm_TGdkGLConfig_has_alpha* = 1 shl 4
|
||||||
|
bp_TGdkGLConfig_has_alpha* = 4
|
||||||
|
bm_TGdkGLConfig_has_depth_buffer* = 1 shl 5
|
||||||
|
bp_TGdkGLConfig_has_depth_buffer* = 5
|
||||||
|
bm_TGdkGLConfig_has_stencil_buffer* = 1 shl 6
|
||||||
|
bp_TGdkGLConfig_has_stencil_buffer* = 6
|
||||||
|
bm_TGdkGLConfig_has_accum_buffer* = 1 shl 7
|
||||||
|
bp_TGdkGLConfig_has_accum_buffer* = 7
|
||||||
|
|
||||||
|
const
|
||||||
|
GDK_GL_MODE_RGB* = 0
|
||||||
|
GDK_GL_MODE_RGBA* = 0
|
||||||
|
GDK_GL_MODE_INDEX* = 1 shl 0
|
||||||
|
GDK_GL_MODE_SINGLE* = 0
|
||||||
|
GDK_GL_MODE_DOUBLE* = 1 shl 1
|
||||||
|
GDK_GL_MODE_STEREO* = 1 shl 2
|
||||||
|
GDK_GL_MODE_ALPHA* = 1 shl 3
|
||||||
|
GDK_GL_MODE_DEPTH* = 1 shl 4
|
||||||
|
GDK_GL_MODE_STENCIL* = 1 shl 5
|
||||||
|
GDK_GL_MODE_ACCUM* = 1 shl 6
|
||||||
|
GDK_GL_MODE_MULTISAMPLE* = 1 shl 7
|
||||||
|
|
||||||
|
type
|
||||||
|
TGdkGLConfigMode* = int32
|
||||||
|
PGdkGLConfigMode* = ptr TGdkGLConfigMode
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_CONFIG*(): GType
|
||||||
|
proc GDK_GL_CONFIG*(anObject: Pointer): PGdkGLConfig
|
||||||
|
proc GDK_GL_CONFIG_CLASS*(klass: Pointer): PGdkGLConfigClass
|
||||||
|
proc GDK_IS_GL_CONFIG*(anObject: Pointer): bool
|
||||||
|
proc GDK_IS_GL_CONFIG_CLASS*(klass: Pointer): bool
|
||||||
|
proc GDK_GL_CONFIG_GET_CLASS*(obj: Pointer): PGdkGLConfigClass
|
||||||
|
proc gdk_gl_config_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_config_get_type".}
|
||||||
|
proc gdk_gl_config_get_screen*(glconfig: PGdkGLConfig): PGdkScreen{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_screen".}
|
||||||
|
proc gdk_gl_config_get_attrib*(glconfig: PGdkGLConfig, attribute: int,
|
||||||
|
value: var cint): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_attrib".}
|
||||||
|
proc gdk_gl_config_get_colormap*(glconfig: PGdkGLConfig): PGdkColormap{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_colormap".}
|
||||||
|
proc gdk_gl_config_get_visual*(glconfig: PGdkGLConfig): PGdkVisual{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_visual".}
|
||||||
|
proc gdk_gl_config_get_depth*(glconfig: PGdkGLConfig): gint{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_depth".}
|
||||||
|
proc gdk_gl_config_get_layer_plane*(glconfig: PGdkGLConfig): gint{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_layer_plane".}
|
||||||
|
proc gdk_gl_config_get_n_aux_buffers*(glconfig: PGdkGLConfig): gint{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_n_aux_buffers".}
|
||||||
|
proc gdk_gl_config_get_n_sample_buffers*(glconfig: PGdkGLConfig): gint{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_get_n_sample_buffers".}
|
||||||
|
proc gdk_gl_config_is_rgba*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_is_rgba".}
|
||||||
|
proc gdk_gl_config_is_double_buffered*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_is_double_buffered".}
|
||||||
|
proc gdk_gl_config_is_stereo*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_is_stereo".}
|
||||||
|
proc gdk_gl_config_has_alpha*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_has_alpha".}
|
||||||
|
proc gdk_gl_config_has_depth_buffer*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_has_depth_buffer".}
|
||||||
|
proc gdk_gl_config_has_stencil_buffer*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_has_stencil_buffer".}
|
||||||
|
proc gdk_gl_config_has_accum_buffer*(glconfig: PGdkGLConfig): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_config_has_accum_buffer".}
|
||||||
|
proc GDK_TYPE_GL_CONTEXT*(): GType
|
||||||
|
proc GDK_GL_CONTEXT*(anObject: Pointer): PGdkGLContext
|
||||||
|
proc GDK_GL_CONTEXT_CLASS*(klass: Pointer): PGdkGLContextClass
|
||||||
|
proc GDK_IS_GL_CONTEXT*(anObject: Pointer): bool
|
||||||
|
proc GDK_IS_GL_CONTEXT_CLASS*(klass: Pointer): bool
|
||||||
|
proc GDK_GL_CONTEXT_GET_CLASS*(obj: Pointer): PGdkGLContextClass
|
||||||
|
proc gdk_gl_context_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_context_get_type".}
|
||||||
|
proc gdk_gl_context_new*(gldrawable: PGdkGLDrawable, share_list: PGdkGLContext,
|
||||||
|
direct: gboolean, render_type: int32): PGdkGLContext{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_context_new".}
|
||||||
|
proc gdk_gl_context_destroy*(glcontext: PGdkGLContext){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_context_destroy".}
|
||||||
|
proc gdk_gl_context_copy*(glcontext: PGdkGLContext, src: PGdkGLContext,
|
||||||
|
mask: int32): gboolean{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_context_copy".}
|
||||||
|
proc gdk_gl_context_get_gl_drawable*(glcontext: PGdkGLContext): PGdkGLDrawable{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_context_get_gl_drawable".}
|
||||||
|
proc gdk_gl_context_get_gl_config*(glcontext: PGdkGLContext): PGdkGLConfig{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_context_get_gl_config".}
|
||||||
|
proc gdk_gl_context_get_share_list*(glcontext: PGdkGLContext): PGdkGLContext{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_context_get_share_list".}
|
||||||
|
proc gdk_gl_context_is_direct*(glcontext: PGdkGLContext): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_context_is_direct".}
|
||||||
|
proc gdk_gl_context_get_render_type*(glcontext: PGdkGLContext): int32{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_context_get_render_type".}
|
||||||
|
proc gdk_gl_context_get_current*(): PGdkGLContext{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_context_get_current".}
|
||||||
|
proc GDK_TYPE_GL_DRAWABLE*(): GType
|
||||||
|
proc GDK_GL_DRAWABLE*(inst: Pointer): PGdkGLDrawable
|
||||||
|
proc GDK_GL_DRAWABLE_CLASS*(vtable: Pointer): PGdkGLDrawableClass
|
||||||
|
proc GDK_IS_GL_DRAWABLE*(inst: Pointer): bool
|
||||||
|
proc GDK_IS_GL_DRAWABLE_CLASS*(vtable: Pointer): bool
|
||||||
|
proc GDK_GL_DRAWABLE_GET_CLASS*(inst: Pointer): PGdkGLDrawableClass
|
||||||
|
proc gdk_gl_drawable_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_get_type".}
|
||||||
|
proc gdk_gl_drawable_make_current*(gldrawable: PGdkGLDrawable,
|
||||||
|
glcontext: PGdkGLContext): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_make_current".}
|
||||||
|
proc gdk_gl_drawable_is_double_buffered*(gldrawable: PGdkGLDrawable): gboolean{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_is_double_buffered".}
|
||||||
|
proc gdk_gl_drawable_swap_buffers*(gldrawable: PGdkGLDrawable){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_swap_buffers".}
|
||||||
|
proc gdk_gl_drawable_wait_gl*(gldrawable: PGdkGLDrawable){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_wait_gl".}
|
||||||
|
proc gdk_gl_drawable_wait_gdk*(gldrawable: PGdkGLDrawable){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_wait_gdk".}
|
||||||
|
proc gdk_gl_drawable_gl_begin*(gldrawable: PGdkGLDrawable,
|
||||||
|
glcontext: PGdkGLContext): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_gl_begin".}
|
||||||
|
proc gdk_gl_drawable_gl_end*(gldrawable: PGdkGLDrawable){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_gl_end".}
|
||||||
|
proc gdk_gl_drawable_get_gl_config*(gldrawable: PGdkGLDrawable): PGdkGLConfig{.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_get_gl_config".}
|
||||||
|
proc gdk_gl_drawable_get_size*(gldrawable: PGdkGLDrawable, width, height: PGInt){.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_drawable_get_size".}
|
||||||
|
proc gdk_gl_drawable_get_current*(): PGdkGLDrawable{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_drawable_get_current".}
|
||||||
|
proc GDK_TYPE_GL_PIXMAP*(): GType
|
||||||
|
proc GDK_GL_PIXMAP*(anObject: Pointer): PGdkGLPixmap
|
||||||
|
proc GDK_GL_PIXMAP_CLASS*(klass: Pointer): PGdkGLPixmapClass
|
||||||
|
proc GDK_IS_GL_PIXMAP*(anObject: Pointer): bool
|
||||||
|
proc GDK_IS_GL_PIXMAP_CLASS*(klass: Pointer): bool
|
||||||
|
proc GDK_GL_PIXMAP_GET_CLASS*(obj: Pointer): PGdkGLPixmapClass
|
||||||
|
proc gdk_gl_pixmap_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_pixmap_get_type".}
|
||||||
|
proc gdk_gl_pixmap_new*(glconfig: PGdkGLConfig, pixmap: PGdkPixmap,
|
||||||
|
attrib_list: ptr int32): PGdkGLPixmap{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_pixmap_new".}
|
||||||
|
proc gdk_gl_pixmap_destroy*(glpixmap: PGdkGLPixmap){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_pixmap_destroy".}
|
||||||
|
proc gdk_gl_pixmap_get_pixmap*(glpixmap: PGdkGLPixmap): PGdkPixmap{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_pixmap_get_pixmap".}
|
||||||
|
proc gdk_pixmap_set_gl_capability*(pixmap: PGdkPixmap, glconfig: PGdkGLConfig,
|
||||||
|
attrib_list: ptr int32): PGdkGLPixmap{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_pixmap_set_gl_capability".}
|
||||||
|
proc gdk_pixmap_unset_gl_capability*(pixmap: PGdkPixmap){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_pixmap_unset_gl_capability".}
|
||||||
|
proc gdk_pixmap_is_gl_capable*(pixmap: PGdkPixmap): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_pixmap_is_gl_capable".}
|
||||||
|
proc gdk_pixmap_get_gl_pixmap*(pixmap: PGdkPixmap): PGdkGLPixmap{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_pixmap_get_gl_pixmap".}
|
||||||
|
proc gdk_pixmap_get_gl_drawable*(pixmap: PGdkPixmap): PGdkGLDrawable
|
||||||
|
proc GDK_TYPE_GL_WINDOW*(): GType
|
||||||
|
proc GDK_GL_WINDOW*(anObject: Pointer): PGdkGLWindow
|
||||||
|
proc GDK_GL_WINDOW_CLASS*(klass: Pointer): PGdkGLWindowClass
|
||||||
|
proc GDK_IS_GL_WINDOW*(anObject: Pointer): bool
|
||||||
|
proc GDK_IS_GL_WINDOW_CLASS*(klass: Pointer): bool
|
||||||
|
proc GDK_GL_WINDOW_GET_CLASS*(obj: Pointer): PGdkGLWindowClass
|
||||||
|
proc gdk_gl_window_get_type*(): GType{.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_window_get_type".}
|
||||||
|
proc gdk_gl_window_new*(glconfig: PGdkGLConfig, window: PGdkWindow,
|
||||||
|
attrib_list: ptr int32): PGdkGLWindow{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_window_new".}
|
||||||
|
proc gdk_gl_window_destroy*(glwindow: PGdkGLWindow){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_window_destroy".}
|
||||||
|
proc gdk_gl_window_get_window*(glwindow: PGdkGLWindow): PGdkWindow{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_window_get_window".}
|
||||||
|
proc gdk_window_set_gl_capability*(window: PGdkWindow, glconfig: PGdkGLConfig,
|
||||||
|
attrib_list: ptr int32): PGdkGLWindow{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_window_set_gl_capability".}
|
||||||
|
proc gdk_window_unset_gl_capability*(window: PGdkWindow){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_window_unset_gl_capability".}
|
||||||
|
proc gdk_window_is_gl_capable*(window: PGdkWindow): gboolean{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_window_is_gl_capable".}
|
||||||
|
proc gdk_window_get_gl_window*(window: PGdkWindow): PGdkGLWindow{.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_window_get_gl_window".}
|
||||||
|
proc gdk_window_get_gl_drawable*(window: PGdkWindow): PGdkGLDrawable
|
||||||
|
proc gdk_gl_draw_cube*(solid: gboolean, size: float64){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_draw_cube".}
|
||||||
|
proc gdk_gl_draw_sphere*(solid: gboolean, radius: float64, slices: int32,
|
||||||
|
stacks: int32){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_draw_sphere".}
|
||||||
|
proc gdk_gl_draw_cone*(solid: gboolean, base: float64, height: float64,
|
||||||
|
slices: int32, stacks: int32){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_draw_cone".}
|
||||||
|
proc gdk_gl_draw_torus*(solid: gboolean, inner_radius: float64,
|
||||||
|
outer_radius: float64, nsides: int32, rings: int32){.
|
||||||
|
cdecl, dynlib: GdkGLExtLib, importc: "gdk_gl_draw_torus".}
|
||||||
|
proc gdk_gl_draw_tetrahedron*(solid: gboolean){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_draw_tetrahedron".}
|
||||||
|
proc gdk_gl_draw_octahedron*(solid: gboolean){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_draw_octahedron".}
|
||||||
|
proc gdk_gl_draw_dodecahedron*(solid: gboolean){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_draw_dodecahedron".}
|
||||||
|
proc gdk_gl_draw_icosahedron*(solid: gboolean){.cdecl, dynlib: GdkGLExtLib,
|
||||||
|
importc: "gdk_gl_draw_icosahedron".}
|
||||||
|
proc gdk_gl_draw_teapot*(solid: gboolean, scale: float64){.cdecl,
|
||||||
|
dynlib: GdkGLExtLib, importc: "gdk_gl_draw_teapot".}
|
||||||
|
proc HEADER_GDKGLEXT_CHECK_VERSION*(major, minor, micro: guint): bool =
|
||||||
|
result = (HEADER_GDKGLEXT_MAJOR_VERSION > major) or
|
||||||
|
((HEADER_GDKGLEXT_MAJOR_VERSION == major) and
|
||||||
|
(HEADER_GDKGLEXT_MINOR_VERSION > minor)) or
|
||||||
|
((HEADER_GDKGLEXT_MAJOR_VERSION == major) and
|
||||||
|
(HEADER_GDKGLEXT_MINOR_VERSION == minor) and
|
||||||
|
(HEADER_GDKGLEXT_MICRO_VERSION >= micro))
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_CONFIG*(): GType =
|
||||||
|
result = gdk_gl_config_get_type()
|
||||||
|
|
||||||
|
proc GDK_GL_CONFIG*(anObject: Pointer): PGdkGLConfig =
|
||||||
|
result = cast[PGdkGLConfig](G_TYPE_CHECK_INSTANCE_CAST(anObject, GDK_TYPE_GL_CONFIG()))
|
||||||
|
|
||||||
|
proc GDK_GL_CONFIG_CLASS*(klass: Pointer): PGdkGLConfigClass =
|
||||||
|
result = cast[PGdkGLConfigClass](G_TYPE_CHECK_CLASS_CAST(klass, GDK_TYPE_GL_CONFIG()))
|
||||||
|
|
||||||
|
proc GDK_IS_GL_CONFIG*(anObject: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_GL_CONFIG())
|
||||||
|
|
||||||
|
proc GDK_IS_GL_CONFIG_CLASS*(klass: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GDK_TYPE_GL_CONFIG())
|
||||||
|
|
||||||
|
proc GDK_GL_CONFIG_GET_CLASS*(obj: Pointer): PGdkGLConfigClass =
|
||||||
|
result = cast[PGdkGLConfigClass](G_TYPE_INSTANCE_GET_CLASS(obj, GDK_TYPE_GL_CONFIG()))
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_CONTEXT*(): GType =
|
||||||
|
result = gdk_gl_context_get_type()
|
||||||
|
|
||||||
|
proc GDK_GL_CONTEXT*(anObject: Pointer): PGdkGLContext =
|
||||||
|
result = cast[PGdkGLContext](G_TYPE_CHECK_INSTANCE_CAST(anObject,
|
||||||
|
GDK_TYPE_GL_CONTEXT()))
|
||||||
|
|
||||||
|
proc GDK_GL_CONTEXT_CLASS*(klass: Pointer): PGdkGLContextClass =
|
||||||
|
result = cast[PGdkGLContextClass](G_TYPE_CHECK_CLASS_CAST(klass, GDK_TYPE_GL_CONTEXT()))
|
||||||
|
|
||||||
|
proc GDK_IS_GL_CONTEXT*(anObject: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_GL_CONTEXT())
|
||||||
|
|
||||||
|
proc GDK_IS_GL_CONTEXT_CLASS*(klass: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GDK_TYPE_GL_CONTEXT())
|
||||||
|
|
||||||
|
proc GDK_GL_CONTEXT_GET_CLASS*(obj: Pointer): PGdkGLContextClass =
|
||||||
|
result = cast[PGdkGLContextClass](G_TYPE_INSTANCE_GET_CLASS(obj, GDK_TYPE_GL_CONTEXT()))
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_DRAWABLE*(): GType =
|
||||||
|
result = gdk_gl_drawable_get_type()
|
||||||
|
|
||||||
|
proc GDK_GL_DRAWABLE*(inst: Pointer): PGdkGLDrawable =
|
||||||
|
result = cast[PGdkGLDrawable](G_TYPE_CHECK_INSTANCE_CAST(inst, GDK_TYPE_GL_DRAWABLE()))
|
||||||
|
|
||||||
|
proc GDK_GL_DRAWABLE_CLASS*(vtable: Pointer): PGdkGLDrawableClass =
|
||||||
|
result = cast[PGdkGLDrawableClass](G_TYPE_CHECK_CLASS_CAST(vtable,
|
||||||
|
GDK_TYPE_GL_DRAWABLE()))
|
||||||
|
|
||||||
|
proc GDK_IS_GL_DRAWABLE*(inst: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(inst, GDK_TYPE_GL_DRAWABLE())
|
||||||
|
|
||||||
|
proc GDK_IS_GL_DRAWABLE_CLASS*(vtable: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(vtable, GDK_TYPE_GL_DRAWABLE())
|
||||||
|
|
||||||
|
proc GDK_GL_DRAWABLE_GET_CLASS*(inst: Pointer): PGdkGLDrawableClass =
|
||||||
|
result = cast[PGdkGLDrawableClass](G_TYPE_INSTANCE_GET_INTERFACE(inst,
|
||||||
|
GDK_TYPE_GL_DRAWABLE()))
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_PIXMAP*(): GType =
|
||||||
|
result = gdk_gl_pixmap_get_type()
|
||||||
|
|
||||||
|
proc GDK_GL_PIXMAP*(anObject: Pointer): PGdkGLPixmap =
|
||||||
|
result = cast[PGdkGLPixmap](G_TYPE_CHECK_INSTANCE_CAST(anObject, GDK_TYPE_GL_PIXMAP()))
|
||||||
|
|
||||||
|
proc GDK_GL_PIXMAP_CLASS*(klass: Pointer): PGdkGLPixmapClass =
|
||||||
|
result = cast[PGdkGLPixmapClass](G_TYPE_CHECK_CLASS_CAST(klass, GDK_TYPE_GL_PIXMAP()))
|
||||||
|
|
||||||
|
proc GDK_IS_GL_PIXMAP*(anObject: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_GL_PIXMAP())
|
||||||
|
|
||||||
|
proc GDK_IS_GL_PIXMAP_CLASS*(klass: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GDK_TYPE_GL_PIXMAP())
|
||||||
|
|
||||||
|
proc GDK_GL_PIXMAP_GET_CLASS*(obj: Pointer): PGdkGLPixmapClass =
|
||||||
|
result = cast[PGdkGLPixmapClass](G_TYPE_INSTANCE_GET_CLASS(obj, GDK_TYPE_GL_PIXMAP()))
|
||||||
|
|
||||||
|
proc gdk_pixmap_get_gl_drawable*(pixmap: PGdkPixmap): PGdkGLDrawable =
|
||||||
|
result = GDK_GL_DRAWABLE(gdk_pixmap_get_gl_pixmap(pixmap))
|
||||||
|
|
||||||
|
proc GDK_TYPE_GL_WINDOW*(): GType =
|
||||||
|
result = gdk_gl_window_get_type()
|
||||||
|
|
||||||
|
proc GDK_GL_WINDOW*(anObject: Pointer): PGdkGLWindow =
|
||||||
|
result = cast[PGdkGLWindow](G_TYPE_CHECK_INSTANCE_CAST(anObject, GDK_TYPE_GL_WINDOW()))
|
||||||
|
|
||||||
|
proc GDK_GL_WINDOW_CLASS*(klass: Pointer): PGdkGLWindowClass =
|
||||||
|
result = cast[PGdkGLWindowClass](G_TYPE_CHECK_CLASS_CAST(klass, GDK_TYPE_GL_WINDOW()))
|
||||||
|
|
||||||
|
proc GDK_IS_GL_WINDOW*(anObject: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(anObject, GDK_TYPE_GL_WINDOW())
|
||||||
|
|
||||||
|
proc GDK_IS_GL_WINDOW_CLASS*(klass: Pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GDK_TYPE_GL_WINDOW())
|
||||||
|
|
||||||
|
proc GDK_GL_WINDOW_GET_CLASS*(obj: Pointer): PGdkGLWindowClass =
|
||||||
|
result = cast[PGdkGLWindowClass](G_TYPE_INSTANCE_GET_CLASS(obj, GDK_TYPE_GL_WINDOW()))
|
||||||
|
|
||||||
|
proc gdk_window_get_gl_drawable*(window: PGdkWindow): PGdkGLDrawable =
|
||||||
|
result = GDK_GL_DRAWABLE(gdk_window_get_gl_window(window))
|
||||||
4498
lib/base/gtk/glib2.nim
Executable file
4498
lib/base/gtk/glib2.nim
Executable file
File diff suppressed because it is too large
Load diff
17226
lib/base/gtk/gtk2.nim
Executable file
17226
lib/base/gtk/gtk2.nim
Executable file
File diff suppressed because it is too large
Load diff
48
lib/base/gtk/gtkglext.nim
Executable file
48
lib/base/gtk/gtkglext.nim
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import
|
||||||
|
Glib2, Gdk2, Gtk2, GdkGLExt
|
||||||
|
|
||||||
|
const
|
||||||
|
GtkGLExtLib* = if defined(WIN32): "libgtkglext-win32-1.0-0.dll" else: "libgtkglext-x11-1.0.so"
|
||||||
|
|
||||||
|
const
|
||||||
|
HEADER_GTKGLEXT_MAJOR_VERSION* = 1
|
||||||
|
HEADER_GTKGLEXT_MINOR_VERSION* = 0
|
||||||
|
HEADER_GTKGLEXT_MICRO_VERSION* = 6
|
||||||
|
HEADER_GTKGLEXT_INTERFACE_AGE* = 4
|
||||||
|
HEADER_GTKGLEXT_BINARY_AGE* = 6
|
||||||
|
|
||||||
|
proc gtk_gl_parse_args*(argc: Plongint, argv: PPPChar): gboolean{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_gl_parse_args".}
|
||||||
|
proc gtk_gl_init_check*(argc: Plongint, argv: PPPChar): gboolean{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_gl_init_check".}
|
||||||
|
proc gtk_gl_init*(argc: Plongint, argv: PPPChar){.cdecl, dynlib: GtkGLExtLib,
|
||||||
|
importc: "gtk_gl_init".}
|
||||||
|
proc gtk_widget_set_gl_capability*(widget: PGtkWidget, glconfig: PGdkGLConfig,
|
||||||
|
share_list: PGdkGLContext, direct: gboolean,
|
||||||
|
render_type: int): gboolean{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_set_gl_capability".}
|
||||||
|
proc gtk_widget_is_gl_capable*(widget: PGtkWidget): gboolean{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_is_gl_capable".}
|
||||||
|
proc gtk_widget_get_gl_config*(widget: PGtkWidget): PGdkGLConfig{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_get_gl_config".}
|
||||||
|
proc gtk_widget_create_gl_context*(widget: PGtkWidget,
|
||||||
|
share_list: PGdkGLContext, direct: gboolean,
|
||||||
|
render_type: int): PGdkGLContext{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_create_gl_context".}
|
||||||
|
proc gtk_widget_get_gl_context*(widget: PGtkWidget): PGdkGLContext{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_get_gl_context".}
|
||||||
|
proc gtk_widget_get_gl_window*(widget: PGtkWidget): PGdkGLWindow{.cdecl,
|
||||||
|
dynlib: GtkGLExtLib, importc: "gtk_widget_get_gl_window".}
|
||||||
|
proc gtk_widget_get_gl_drawable*(widget: PGtkWidget): PGdkGLDrawable =
|
||||||
|
nil
|
||||||
|
|
||||||
|
proc HEADER_GTKGLEXT_CHECK_VERSION*(major, minor, micro: guint): bool =
|
||||||
|
result = (HEADER_GTKGLEXT_MAJOR_VERSION > major) or
|
||||||
|
((HEADER_GTKGLEXT_MAJOR_VERSION == major) and
|
||||||
|
(HEADER_GTKGLEXT_MINOR_VERSION > minor)) or
|
||||||
|
((HEADER_GTKGLEXT_MAJOR_VERSION == major) and
|
||||||
|
(HEADER_GTKGLEXT_MINOR_VERSION == minor) and
|
||||||
|
(HEADER_GTKGLEXT_MICRO_VERSION >= micro))
|
||||||
|
|
||||||
|
proc gtk_widget_get_gl_drawable*(widget: PGtkWidget): PGdkGLDrawable =
|
||||||
|
result = GDK_GL_DRAWABLE(gtk_widget_get_gl_window(widget))
|
||||||
497
lib/base/gtk/gtkhtml.nim
Executable file
497
lib/base/gtk/gtkhtml.nim
Executable file
|
|
@ -0,0 +1,497 @@
|
||||||
|
import
|
||||||
|
gtk2, glib2, atk, pango, gdk2pixbuf, gdk2
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
{.define: GTK_WINDOWING_WIN32.}
|
||||||
|
const
|
||||||
|
gtkhtmllib = "libgtkhtml-win32-2.0-0.dll"
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
gtkhtmllib = "libgtkhtml-2.so"
|
||||||
|
const
|
||||||
|
DOM_UNSPECIFIED_EVENT_TYPE_ERR* = 0
|
||||||
|
DOM_INDEX_SIZE_ERR* = 1
|
||||||
|
DOM_DOMSTRING_SIZE_ERR* = 2
|
||||||
|
DOM_HIERARCHY_REQUEST_ERR* = 3
|
||||||
|
DOM_WRONG_DOCUMENT_ERR* = 4
|
||||||
|
DOM_INVALID_CHARACTER_ERR* = 5
|
||||||
|
DOM_NO_DATA_ALLOWED_ERR* = 6
|
||||||
|
DOM_NO_MODIFICATION_ALLOWED_ERR* = 7
|
||||||
|
DOM_NOT_FOUND_ERR* = 8
|
||||||
|
DOM_NOT_SUPPORTED_ERR* = 9
|
||||||
|
DOM_INUSE_ATTRIBUTE_ERR* = 10
|
||||||
|
DOM_INVALID_STATE_ERR* = 11
|
||||||
|
DOM_SYNTAX_ERR* = 12
|
||||||
|
DOM_INVALID_MODIFICATION_ERR* = 13
|
||||||
|
DOM_NAMESPACE_ERR* = 14
|
||||||
|
DOM_INVALID_ACCESS_ERR* = 15
|
||||||
|
DOM_NO_EXCEPTION* = 255
|
||||||
|
DOM_ELEMENT_NODE* = 1
|
||||||
|
DOM_ATTRIBUTE_NODE* = 2
|
||||||
|
DOM_TEXT_NODE* = 3
|
||||||
|
DOM_CDATA_SECTION_NODE* = 4
|
||||||
|
DOM_ENTITY_REFERENCE_NODE* = 5
|
||||||
|
DOM_ENTITY_NODE* = 6
|
||||||
|
DOM_PROCESSING_INSTRUCTION_NODE* = 7
|
||||||
|
DOM_COMMENT_NODE* = 8
|
||||||
|
DOM_DOCUMENT_NODE* = 9
|
||||||
|
DOM_DOCUMENT_TYPE_NODE* = 10
|
||||||
|
DOM_DOCUMENT_FRAGMENT_NODE* = 11
|
||||||
|
DOM_NOTATION_NODE* = 12
|
||||||
|
bm__HtmlFontSpecification_weight* = 0x0000000F
|
||||||
|
bp__HtmlFontSpecification_weight* = 0
|
||||||
|
bm__HtmlFontSpecification_style* = 0x00000030
|
||||||
|
bp__HtmlFontSpecification_style* = 4
|
||||||
|
bm__HtmlFontSpecification_variant* = 0x000000C0
|
||||||
|
bp__HtmlFontSpecification_variant* = 6
|
||||||
|
bm__HtmlFontSpecification_stretch* = 0x00000F00
|
||||||
|
bp__HtmlFontSpecification_stretch* = 8
|
||||||
|
bm__HtmlFontSpecification_decoration* = 0x00007000
|
||||||
|
bp__HtmlFontSpecification_decoration* = 12
|
||||||
|
|
||||||
|
type
|
||||||
|
TDomString* = gchar
|
||||||
|
TDomBoolean* = gboolean
|
||||||
|
TDomException* = gushort
|
||||||
|
TDomTimeStamp* = guint64
|
||||||
|
PDomNode* = ptr TDomNode
|
||||||
|
TDomNode* = object of TGObject
|
||||||
|
xmlnode*: pointer
|
||||||
|
style*: pointer
|
||||||
|
|
||||||
|
PDomNodeClass* = ptr TDomNodeClass
|
||||||
|
TDomNodeClass* = object of TGObjectClass
|
||||||
|
`get_nodeName`*: proc (node: PDomNode): PDomString{.cdecl.}
|
||||||
|
`get_nodeValue`*: proc (node: PDomNode, exc: PDomException): PDomString {.
|
||||||
|
cdecl.}
|
||||||
|
`set_nodeValue`*: proc (node: PDomNode, value: PDomString,
|
||||||
|
exc: PDomException): PDomString{.cdecl.}
|
||||||
|
|
||||||
|
PDomDocument* = ptr TDomDocument
|
||||||
|
TDomDocument* = record
|
||||||
|
parent*: PDomNode
|
||||||
|
iterators*: PGSList
|
||||||
|
|
||||||
|
PDomDocumentClass* = ptr TDomDocumentClass
|
||||||
|
TDomDocumentClass* = record
|
||||||
|
parent_class*: PDomNodeClass
|
||||||
|
|
||||||
|
PHtmlFocusIterator* = ptr THtmlFocusIterator
|
||||||
|
THtmlFocusIterator* = object of TGObject
|
||||||
|
document*: PDomDocument
|
||||||
|
current_node*: PDomNode
|
||||||
|
|
||||||
|
PHtmlFocusIteratorClass* = ptr THtmlFocusIteratorClass
|
||||||
|
THtmlFocusIteratorClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
THtmlParserType* = enum
|
||||||
|
HTML_PARSER_TYPE_HTML, HTML_PARSER_TYPE_XML
|
||||||
|
PHtmlParser* = ptr THtmlParser
|
||||||
|
THtmlParser* = object of TGObject
|
||||||
|
parser_type*: THtmlParserType
|
||||||
|
document*: PHtmlDocument
|
||||||
|
stream*: PHtmlStream
|
||||||
|
xmlctxt*: xmlParserCtxtPtr
|
||||||
|
res*: int32
|
||||||
|
chars*: array[0..9, char]
|
||||||
|
blocking*: gboolean
|
||||||
|
blocking_node*: PDomNode
|
||||||
|
|
||||||
|
PHtmlParserClass* = ptr THtmlParserClass
|
||||||
|
THtmlParserClass* = object of TGtkObjectClass
|
||||||
|
done_parsing*: proc (parser: PHtmlParser){.cdecl.}
|
||||||
|
new_node*: proc (parser: PHtmlParser, node: PDomNode)
|
||||||
|
parsed_document_node*: proc (parser: PHtmlParser, document: PDomDocument)
|
||||||
|
|
||||||
|
PHtmlStream* = ptr THtmlStream
|
||||||
|
THtmlStreamCloseFunc* = proc (stream: PHtmlStream, user_data: gpointer){.cdecl.}
|
||||||
|
THtmlStreamWriteFunc* = proc (stream: PHtmlStream, buffer: Pgchar,
|
||||||
|
size: guint, user_data: gpointer){.cdecl.}
|
||||||
|
THtmlStreamCancelFunc* = proc (stream: PHtmlStream, user_data: gpointer,
|
||||||
|
cancel_data: gpointer){.cdecl.}
|
||||||
|
THtmlStream* = object of TGObject
|
||||||
|
write_func*: THtmlStreamWriteFunc
|
||||||
|
close_func*: THtmlStreamCloseFunc
|
||||||
|
cancel_func*: THtmlStreamCancelFunc
|
||||||
|
user_data*: gpointer
|
||||||
|
cancel_data*: gpointer
|
||||||
|
written*: gint
|
||||||
|
mime_type*: cstring
|
||||||
|
|
||||||
|
PHtmlStreamClass* = ptr THtmlStreamClass
|
||||||
|
THtmlStreamClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
THtmlStreamBufferCloseFunc* = proc (str: Pgchar, len: gint,
|
||||||
|
user_data: gpointer){.cdecl.}
|
||||||
|
PGtkHtmlContext* = ptr TGtkHtmlContext
|
||||||
|
TGtkHtmlContext* = object of TGObject
|
||||||
|
documents*: PGSList
|
||||||
|
standard_font*: PHtmlFontSpecification
|
||||||
|
fixed_font*: PHtmlFontSpecification
|
||||||
|
debug_painting*: gboolean
|
||||||
|
|
||||||
|
PGtkHtmlContextClass* = ptr TGtkHtmlContextClass
|
||||||
|
TGtkHtmlContextClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
THtmlDocumentState* = enum
|
||||||
|
HTML_DOCUMENT_STATE_DONE, HTML_DOCUMENT_STATE_PARSING
|
||||||
|
PHtmlDocument* = ptr THtmlDocument
|
||||||
|
THtmlDocument* = object of TGObject
|
||||||
|
stylesheets*: PGSList
|
||||||
|
current_stream*: PHtmlStream
|
||||||
|
state*: THtmlDocumentState
|
||||||
|
|
||||||
|
PHtmlDocumentClass* = ptr THtmlDocumentClass
|
||||||
|
THtmlDocumentClass* = object of TGObjectClass
|
||||||
|
request_url*: proc (document: PHtmlDocument, url: Pgchar,
|
||||||
|
stream: PHtmlStream){.cdecl.}
|
||||||
|
link_clicked*: proc (document: PHtmlDocument, url: Pgchar){.cdecl.}
|
||||||
|
set_base*: proc (document: PHtmlDocument, url: Pgchar){.cdecl.}
|
||||||
|
title_changed*: proc (document: PHtmlDocument, new_title: Pgchar){.cdecl.}
|
||||||
|
submit*: proc (document: PHtmlDocument, `method`: Pgchar, url: Pgchar,
|
||||||
|
encoding: Pgchar){.cdecl.}
|
||||||
|
|
||||||
|
PHtmlView* = ptr THtmlView
|
||||||
|
THtmlView* = object of TGtkLayout
|
||||||
|
document*: PHtmlDocument
|
||||||
|
node_table*: PGHashTable
|
||||||
|
relayout_idle_id*: guint
|
||||||
|
relayout_timeout_id*: guint
|
||||||
|
mouse_down_x*: gint
|
||||||
|
mouse_down_y*: gint
|
||||||
|
mouse_detail*: gint
|
||||||
|
sel_start_ypos*: gint
|
||||||
|
sel_start_index*: gint
|
||||||
|
sel_end_ypos*: gint
|
||||||
|
sel_end_index*: gint
|
||||||
|
sel_flag*: gboolean
|
||||||
|
sel_backwards*: gboolean
|
||||||
|
sel_start_found*: gboolean
|
||||||
|
sel_list*: PGSList
|
||||||
|
jump_to_anchor*: pgchar
|
||||||
|
magnification*: gdouble
|
||||||
|
magnification_modified*: gboolean
|
||||||
|
on_url*: gboolean
|
||||||
|
|
||||||
|
PHtmlViewClass* = ptr THtmlViewClass
|
||||||
|
THtmlViewClass* = object of TGtkLayoutClass
|
||||||
|
move_cursor*: proc (html_view: PHtmlView, step: TGtkMovementStep,
|
||||||
|
count: gint, extend_selection: gboolean){.cdecl.}
|
||||||
|
on_url*: proc (html_view: PHtmlView, url: Pgchar)
|
||||||
|
activate*: proc (html_view: PHtmlView)
|
||||||
|
move_focus_out*: proc (html_view: PHtmlView, direction: TGtkDirectionType)
|
||||||
|
|
||||||
|
|
||||||
|
proc DOM_TYPE_NODE*(): GType
|
||||||
|
proc DOM_NODE*(theobject: pointer): PDomNode
|
||||||
|
proc DOM_NODE_CLASS*(klass: pointer): PDomNodeClass
|
||||||
|
proc DOM_IS_NODE*(theobject: pointer): bool
|
||||||
|
proc DOM_IS_NODE_CLASS*(klass: pointer): bool
|
||||||
|
proc DOM_NODE_GET_CLASS*(obj: pointer): int32
|
||||||
|
proc dom_node_get_type*(): GType{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "dom_node_get_type".}
|
||||||
|
proc dom_Node_mkref*(node: pointer): PDomNode{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "dom_Node_mkref".}
|
||||||
|
proc dom_Node__get_childNodes*(node: PDomNode): PDomNodeList{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_childNodes".}
|
||||||
|
proc dom_Node_removeChild*(node: PDomNode, oldChild: PDomNode,
|
||||||
|
exc: PDomException): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_removeChild".}
|
||||||
|
proc dom_Node__get_nodeValue*(node: PDomNode, exc: PDomException): PDomString{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "dom_Node__get_nodeValue".}
|
||||||
|
proc dom_Node__get_firstChild*(node: PDomNode): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_firstChild".}
|
||||||
|
proc dom_Node__get_nodeName*(node: PDomNode): PDomString{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_nodeName".}
|
||||||
|
proc dom_Node__get_attributes*(node: PDomNode): PDomNamedNodeMap{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_attributes".}
|
||||||
|
proc dom_Document__get_doctype*(doc: PDomDocument): PDomDocumentType{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Document__get_doctype".}
|
||||||
|
proc dom_Node_hasChildNodes*(node: PDomNode): DomBoolean{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_hasChildNodes".}
|
||||||
|
proc dom_Node__get_parentNode*(node: PDomNode): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_parentNode".}
|
||||||
|
proc dom_Node__get_nextSibling*(node: PDomNode): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_nextSibling".}
|
||||||
|
proc dom_Node__get_nodeType*(node: PDomNode): gushort{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_nodeType".}
|
||||||
|
proc dom_Node_hasAttributes*(node: PDomNode): DomBoolean{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_hasAttributes".}
|
||||||
|
proc dom_Node_cloneNode*(node: PDomNode, deep: DomBoolean): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_cloneNode".}
|
||||||
|
proc dom_Node_appendChild*(node: PDomNode, newChild: PDomNode,
|
||||||
|
exc: PDomException): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_appendChild".}
|
||||||
|
proc dom_Node__get_localName*(node: PDomNode): PDomString{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_localName".}
|
||||||
|
proc dom_Node__get_namespaceURI*(node: PDomNode): PDomString{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_namespaceURI".}
|
||||||
|
proc dom_Node__get_previousSibling*(node: PDomNode): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_previousSibling".}
|
||||||
|
proc dom_Node__get_lastChild*(node: PDomNode): PDomNode{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_lastChild".}
|
||||||
|
proc dom_Node__set_nodeValue*(node: PDomNode, value: PDomString,
|
||||||
|
exc: PDomException){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "dom_Node__set_nodeValue".}
|
||||||
|
proc dom_Node__get_ownerDocument*(node: PDomNode): PDomDocument{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node__get_ownerDocument".}
|
||||||
|
proc dom_Node_hasAttributes*(node: PDomNode): gboolean{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "dom_Node_hasAttributes".}
|
||||||
|
proc DOM_TYPE_DOCUMENT*(): GType
|
||||||
|
proc DOM_DOCUMENT*(theobject: pointer): PDomDocument
|
||||||
|
proc DOM_DOCUMENT_CLASS*(klass: pointer): PDomDocumentClass
|
||||||
|
proc DOM_IS_DOCUMENT*(theobject: pointer): bool
|
||||||
|
proc DOM_IS_DOCUMENT_CLASS*(klass: pointer): bool
|
||||||
|
proc DOM_DOCUMENT_GET_CLASS*(obj: pointer): PDomDocumentClass
|
||||||
|
proc dom_document_get_type*(): GType
|
||||||
|
proc dom_Document__get_documentElement*(doc: PDomDocument): PDomElement
|
||||||
|
proc dom_Document_createElement*(doc: PDomDocument, tagName: PDomString): PDomElement
|
||||||
|
proc dom_Document_createTextNode*(doc: PDomDocument, data: PDomString): PDomText
|
||||||
|
proc dom_Document_createComment*(doc: PDomDocument, data: PDomString): PDomComment
|
||||||
|
proc dom_Document_importNode*(doc: PDomDocument, importedNode: PDomNode,
|
||||||
|
deep: DomBoolean, exc: PDomException): PDomNode
|
||||||
|
proc HTML_TYPE_FOCUS_ITERATOR*(): GType
|
||||||
|
proc HTML_FOCUS_ITERATOR*(theobject: pointer): PHtmlFocusIterator
|
||||||
|
proc HTML_FOCUS_ITERATOR_CLASS*(klass: pointer): PHtmlFocusIteratorClass
|
||||||
|
proc HTML_IS_FOCUS_ITERATOR*(theobject: pointer): bool
|
||||||
|
proc HTML_IS_FOCUS_ITERATOR_CLASS*(klass: pointer): bool
|
||||||
|
proc HTML_FOCUS_ITERATOR_GET_CLASS*(obj: pointer): PHtmlFocusIteratorClass
|
||||||
|
proc html_focus_iterator_next_element*(document: PDomDocument,
|
||||||
|
element: PDomElement): PDomElement{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_focus_iterator_next_element".}
|
||||||
|
proc html_focus_iterator_prev_element*(document: PDomDocument,
|
||||||
|
element: PDomElement): PDomElement{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_focus_iterator_prev_element".}
|
||||||
|
proc HTML_PARSER_TYPE*(): GType
|
||||||
|
proc HTML_PARSER*(obj: pointer): PHtmlParser
|
||||||
|
proc HTML_PARSER_CLASS*(klass: pointer): PHtmlParserClass
|
||||||
|
proc HTML_IS_PARSER*(obj: pointer): bool
|
||||||
|
proc html_parser_get_type*(): GType
|
||||||
|
proc html_parser_new*(document: PHtmlDocument, parser_type: THtmlParserType): PHtmlParser
|
||||||
|
proc HTML_TYPE_STREAM*(): GType
|
||||||
|
proc HTML_STREAM*(obj: pointer): PHtmlStream
|
||||||
|
proc HTML_STREAM_CLASS*(klass: pointer): PHtmlStreamClass
|
||||||
|
proc HTML_IS_STREAM*(obj: pointer): bool
|
||||||
|
proc HTML_IS_STREAM_CLASS*(klass: pointer): bool
|
||||||
|
proc HTML_STREAM_GET_CLASS*(obj: pointer): PHtmlStreamClass
|
||||||
|
proc html_stream_get_type*(): GType{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_stream_get_type".}
|
||||||
|
proc html_stream_new*(write_func: THtmlStreamWriteFunc,
|
||||||
|
close_func: THtmlStreamCloseFunc, user_data: gpointer): PHtmlStream{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_stream_new".}
|
||||||
|
proc html_stream_write*(stream: PHtmlStream, buffer: Pgchar, size: guint){.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_stream_write".}
|
||||||
|
proc html_stream_close*(stream: PHtmlStream){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_stream_close".}
|
||||||
|
proc html_stream_destroy*(stream: PHtmlStream){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_stream_destroy".}
|
||||||
|
proc html_stream_get_written*(stream: PHtmlStream): gint{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_stream_get_written".}
|
||||||
|
proc html_stream_cancel*(stream: PHtmlStream){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_stream_cancel".}
|
||||||
|
proc html_stream_set_cancel_func*(stream: PHtmlStream,
|
||||||
|
abort_func: THtmlStreamCancelFunc,
|
||||||
|
cancel_data: gpointer){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_stream_set_cancel_func".}
|
||||||
|
proc html_stream_get_mime_type*(stream: PHtmlStream): cstring{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_stream_get_mime_type".}
|
||||||
|
proc html_stream_set_mime_type*(stream: PHtmlStream, mime_type: cstring){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_stream_set_mime_type".}
|
||||||
|
proc html_stream_buffer_new*(close_func: THtmlStreamBufferCloseFunc,
|
||||||
|
user_data: gpointer): PHtmlStream{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_stream_buffer_new".}
|
||||||
|
proc html_event_mouse_move*(view: PHtmlView, event: PGdkEventMotion){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_event_mouse_move".}
|
||||||
|
proc html_event_button_press*(view: PHtmlView, button: PGdkEventButton){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_event_button_press".}
|
||||||
|
proc html_event_button_release*(view: PHtmlView, event: PGdkEventButton){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_event_button_release".}
|
||||||
|
proc html_event_activate*(view: PHtmlView){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_event_activate".}
|
||||||
|
proc html_event_key_press*(view: PHtmlView, event: PGdkEventKey): gboolean{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_event_key_press".}
|
||||||
|
proc html_event_find_root_box*(self: PHtmlBox, x: gint, y: gint): PHtmlBox{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_event_find_root_box".}
|
||||||
|
proc html_selection_start*(view: PHtmlView, event: PGdkEventButton){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_selection_start".}
|
||||||
|
proc html_selection_end*(view: PHtmlView, event: PGdkEventButton){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_selection_end".}
|
||||||
|
proc html_selection_update*(view: PHtmlView, event: PGdkEventMotion){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_selection_update".}
|
||||||
|
proc html_selection_clear*(view: PHtmlView){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_selection_clear".}
|
||||||
|
proc html_selection_set*(view: PHtmlView, start: PDomNode, offset: int32,
|
||||||
|
len: int32){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_selection_set".}
|
||||||
|
proc GTK_HTML_CONTEXT_TYPE*(): GType
|
||||||
|
proc GTK_HTML_CONTEXT*(obj: pointer): PGtkHtmlContext
|
||||||
|
proc GTK_HTML_CONTEXT_CLASS*(klass: pointer): PGtkHtmlContextClass
|
||||||
|
proc GTK_HTML_IS_CONTEXT*(obj: pointer): bool
|
||||||
|
proc GTK_HTML_IS_CONTEXT_CLASS*(klass: pointer): bool
|
||||||
|
proc gtk_html_context_get_type*(): GType
|
||||||
|
proc gtk_html_context_get*(): PGtkHtmlContext
|
||||||
|
proc HTML_TYPE_DOCUMENT*(): GType
|
||||||
|
proc HTML_DOCUMENT*(obj: pointer): PHtmlDocument
|
||||||
|
proc HTML_DOCUMENT_CLASS*(klass: pointer): PHtmlDocumentClass
|
||||||
|
proc HTML_IS_DOCUMENT*(obj: pointer): bool
|
||||||
|
proc html_document_get_type*(): GType{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_document_get_type".}
|
||||||
|
proc html_document_new*(): PHtmlDocument{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_document_new".}
|
||||||
|
proc html_document_open_stream*(document: PHtmlDocument, mime_type: Pgchar): gboolean{.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_document_open_stream".}
|
||||||
|
proc html_document_write_stream*(document: PHtmlDocument, buffer: Pgchar,
|
||||||
|
len: gint){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_document_write_stream".}
|
||||||
|
proc html_document_close_stream*(document: PHtmlDocument){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_document_close_stream".}
|
||||||
|
proc html_document_clear*(document: PHtmlDocument){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_document_clear".}
|
||||||
|
proc HTML_TYPE_VIEW*(): GType
|
||||||
|
proc HTML_VIEW*(obj: pointer): PHtmlView
|
||||||
|
proc HTML_VIEW_CLASS*(klass: pointer): PHtmlViewClass
|
||||||
|
proc HTML_IS_VIEW*(obj: pointer): bool
|
||||||
|
proc html_view_get_type*(): GType{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_view_get_type".}
|
||||||
|
proc html_view_new*(): PGtkWidget{.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_view_new".}
|
||||||
|
proc html_view_set_document*(view: PHtmlView, document: PHtmlDocument){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_view_set_document".}
|
||||||
|
proc html_view_jump_to_anchor*(view: PHtmlView, anchor: Pgchar){.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_view_jump_to_anchor".}
|
||||||
|
proc html_view_get_magnification*(view: PHtmlView): gdouble{.cdecl,
|
||||||
|
dynlib: gtkhtmllib, importc: "html_view_get_magnification".}
|
||||||
|
proc html_view_set_magnification*(view: PHtmlView, magnification: gdouble){.
|
||||||
|
cdecl, dynlib: gtkhtmllib, importc: "html_view_set_magnification".}
|
||||||
|
proc html_view_zoom_in*(view: PHtmlView){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_view_zoom_in".}
|
||||||
|
proc html_view_zoom_out*(view: PHtmlView){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_view_zoom_out".}
|
||||||
|
proc html_view_zoom_reset*(view: PHtmlView){.cdecl, dynlib: gtkhtmllib,
|
||||||
|
importc: "html_view_zoom_reset".}
|
||||||
|
proc DOM_TYPE_NODE*(): GType =
|
||||||
|
result = dom_node_get_type()
|
||||||
|
|
||||||
|
proc DOM_NODE*(theobject: pointer): PDomNode =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_CAST(theobject, DOM_TYPE_NODE(), TDomNode)
|
||||||
|
|
||||||
|
proc DOM_NODE_CLASS*(klass: pointer): PDomNodeClass =
|
||||||
|
result = G_TYPE_CHECK_CLASS_CAST(klass, DOM_TYPE_NODE(), TDomNodeClass)
|
||||||
|
|
||||||
|
proc DOM_IS_NODE*(theobject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(theobject, DOM_TYPE_NODE())
|
||||||
|
|
||||||
|
proc DOM_IS_NODE_CLASS*(klass: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, DOM_TYPE_NODE())
|
||||||
|
|
||||||
|
proc DOM_NODE_GET_CLASS*(obj: pointer): PDomNodeClass =
|
||||||
|
result = G_TYPE_INSTANCE_GET_CLASS(obj, DOM_TYPE_NODE(), TDomNodeClass)
|
||||||
|
|
||||||
|
proc DOM_TYPE_DOCUMENT*(): GType =
|
||||||
|
result = dom_document_get_type()
|
||||||
|
|
||||||
|
proc DOM_DOCUMENT*(theobject: pointer): PDomDocument =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_CAST(theobject, DOM_TYPE_DOCUMENT(), TDomDocument)
|
||||||
|
|
||||||
|
proc DOM_DOCUMENT_CLASS*(klass: pointer): PDomDocumentClass =
|
||||||
|
result = G_TYPE_CHECK_CLASS_CAST(klass, DOM_TYPE_DOCUMENT(), TDomDocumentClass)
|
||||||
|
|
||||||
|
proc DOM_IS_DOCUMENT*(theobject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(theobject, DOM_TYPE_DOCUMENT())
|
||||||
|
|
||||||
|
proc DOM_IS_DOCUMENT_CLASS*(klass: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, DOM_TYPE_DOCUMENT())
|
||||||
|
|
||||||
|
proc DOM_DOCUMENT_GET_CLASS*(obj: pointer): PDomDocumentClass =
|
||||||
|
result = G_TYPE_INSTANCE_GET_CLASS(obj, DOM_TYPE_DOCUMENT(), TDomDocumentClass)
|
||||||
|
|
||||||
|
proc HTML_TYPE_FOCUS_ITERATOR*(): GType =
|
||||||
|
result = html_focus_iterator_get_type()
|
||||||
|
|
||||||
|
proc HTML_FOCUS_ITERATOR*(theobject: pointer): PHtmlFocusIterator =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_CAST(theobject, HTML_TYPE_FOCUS_ITERATOR(),
|
||||||
|
HtmlFocusIterator)
|
||||||
|
|
||||||
|
proc HTML_FOCUS_ITERATOR_CLASS*(klass: pointer): PHtmlFocusIteratorClass =
|
||||||
|
result = G_TYPE_CHECK_CLASS_CAST(klass, HTML_TYPE_FOCUS_ITERATOR(),
|
||||||
|
HtmlFocusIteratorClass)
|
||||||
|
|
||||||
|
proc HTML_IS_FOCUS_ITERATOR*(theobject: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(theobject, HTML_TYPE_FOCUS_ITERATOR())
|
||||||
|
|
||||||
|
proc HTML_IS_FOCUS_ITERATOR_CLASS*(klass: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, HTML_TYPE_FOCUS_ITERATOR())
|
||||||
|
|
||||||
|
proc HTML_FOCUS_ITERATOR_GET_CLASS*(obj: pointer): PHtmlFocusIteratorClass =
|
||||||
|
result = G_TYPE_INSTANCE_GET_CLASS(obj, HTML_TYPE_FOCUS_ITERATOR(),
|
||||||
|
HtmlFocusIteratorClass)
|
||||||
|
|
||||||
|
proc HTML_PARSER_TYPE*(): GType =
|
||||||
|
result = html_parser_get_type()
|
||||||
|
|
||||||
|
proc HTML_PARSER*(obj: pointer): PHtmlParser =
|
||||||
|
result = GTK_CHECK_CAST(obj, HTML_PARSER_TYPE(), THtmlParser)
|
||||||
|
|
||||||
|
proc HTML_PARSER_CLASS*(klass: pointer): PHtmlParserClass =
|
||||||
|
result = GTK_CHECK_CLASS_CAST(klass, HTML_PARSER_TYPE(), THtmlParserClass)
|
||||||
|
|
||||||
|
proc HTML_IS_PARSER*(obj: pointer): bool =
|
||||||
|
result = GTK_CHECK_TYPE(obj, HTML_PARSER_TYPE())
|
||||||
|
|
||||||
|
proc HTML_TYPE_STREAM*(): GType =
|
||||||
|
result = html_stream_get_type()
|
||||||
|
|
||||||
|
proc HTML_STREAM*(obj: pointer): PHtmlStream =
|
||||||
|
result = PHtmlStream(G_TYPE_CHECK_INSTANCE_CAST(obj, HTML_TYPE_STREAM()))
|
||||||
|
|
||||||
|
proc HTML_STREAM_CLASS*(klass: pointer): PHtmlStreamClass =
|
||||||
|
result = G_TYPE_CHECK_CLASS_CAST(klass, HTML_TYPE_STREAM())
|
||||||
|
|
||||||
|
proc HTML_IS_STREAM*(obj: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(obj, HTML_TYPE_STREAM())
|
||||||
|
|
||||||
|
proc HTML_IS_STREAM_CLASS*(klass: pointer): bool =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, HTML_TYPE_STREAM())
|
||||||
|
|
||||||
|
proc HTML_STREAM_GET_CLASS*(obj: pointer): PHtmlStreamClass =
|
||||||
|
result = PHtmlStreamClass(G_TYPE_INSTANCE_GET_CLASS(obj, HTML_TYPE_STREAM()))
|
||||||
|
|
||||||
|
proc GTK_HTML_CONTEXT_TYPE*(): GType =
|
||||||
|
result = gtk_html_context_get_type()
|
||||||
|
|
||||||
|
proc GTK_HTML_CONTEXT*(obj: pointer): PGtkHtmlContext =
|
||||||
|
result = GTK_CHECK_CAST(obj, GTK_HTML_CONTEXT_TYPE(), TGtkHtmlContext)
|
||||||
|
|
||||||
|
proc GTK_HTML_CONTEXT_CLASS*(klass: pointer): PGtkHtmlContextClass =
|
||||||
|
result = GTK_CHECK_CLASS_CAST(klass, GTK_HTML_CONTEXT_TYPE(),
|
||||||
|
TGtkHtmlContextClass)
|
||||||
|
|
||||||
|
proc GTK_HTML_IS_CONTEXT*(obj: pointer): bool =
|
||||||
|
result = GTK_CHECK_TYPE(obj, GTK_HTML_CONTEXT_TYPE())
|
||||||
|
|
||||||
|
proc GTK_HTML_IS_CONTEXT_CLASS*(klass: pointer): bool =
|
||||||
|
result = GTK_CHECK_CLASS_TYPE(klass, GTK_HTML_CONTEXT_TYPE())
|
||||||
|
|
||||||
|
proc HTML_TYPE_DOCUMENT*(): GType =
|
||||||
|
result = html_document_get_type()
|
||||||
|
|
||||||
|
proc HTML_DOCUMENT*(obj: pointer): PHtmlDocument =
|
||||||
|
result = PHtmlDocument(GTK_CHECK_CAST(obj, HTML_TYPE_DOCUMENT()))
|
||||||
|
|
||||||
|
proc HTML_DOCUMENT_CLASS*(klass: pointer): PHtmlDocumentClass =
|
||||||
|
result = GTK_CHECK_CLASS_CAST(klass, HTML_TYPE_DOCUMENT())
|
||||||
|
|
||||||
|
proc HTML_IS_DOCUMENT*(obj: pointer): bool =
|
||||||
|
result = GTK_CHECK_TYPE(obj, HTML_TYPE_DOCUMENT())
|
||||||
|
|
||||||
|
proc HTML_TYPE_VIEW*(): GType =
|
||||||
|
result = html_view_get_type()
|
||||||
|
|
||||||
|
proc HTML_VIEW*(obj: pointer): PHtmlView =
|
||||||
|
result = PHtmlView(GTK_CHECK_CAST(obj, HTML_TYPE_VIEW()))
|
||||||
|
|
||||||
|
proc HTML_VIEW_CLASS*(klass: pointer): PHtmlViewClass =
|
||||||
|
result = PHtmlViewClass(GTK_CHECK_CLASS_CAST(klass, HTML_TYPE_VIEW()))
|
||||||
|
|
||||||
|
proc HTML_IS_VIEW*(obj: pointer): bool =
|
||||||
|
result = GTK_CHECK_TYPE(obj, HTML_TYPE_VIEW())
|
||||||
117
lib/base/gtk/libglade2.nim
Executable file
117
lib/base/gtk/libglade2.nim
Executable file
|
|
@ -0,0 +1,117 @@
|
||||||
|
import
|
||||||
|
glib2, gtk2
|
||||||
|
|
||||||
|
when defined(win32):
|
||||||
|
{.define: gtkwin.}
|
||||||
|
const
|
||||||
|
LibGladeLib = "libglade-2.0-0.dll"
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
LibGladeLib = "libglade-2.0.so"
|
||||||
|
type
|
||||||
|
PLongint* = ptr int32
|
||||||
|
PSmallInt* = ptr int16
|
||||||
|
PByte* = ptr int8
|
||||||
|
PWord* = ptr int16
|
||||||
|
PDWord* = ptr int32
|
||||||
|
PDouble* = ptr float64
|
||||||
|
|
||||||
|
proc glade_init*(){.cdecl, dynlib: LibGladeLib, importc: "glade_init".}
|
||||||
|
proc glade_require*(TheLibrary: cstring){.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_require".}
|
||||||
|
proc glade_provide*(TheLibrary: cstring){.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_provide".}
|
||||||
|
type
|
||||||
|
PGladeXMLPrivate* = pointer
|
||||||
|
PGladeXML* = ptr TGladeXML
|
||||||
|
TGladeXML* = object of TGObject
|
||||||
|
filename*: cstring
|
||||||
|
priv*: PGladeXMLPrivate
|
||||||
|
|
||||||
|
PGladeXMLClass* = ptr TGladeXMLClass
|
||||||
|
TGladeXMLClass* = object of TGObjectClass
|
||||||
|
|
||||||
|
TGladeXMLConnectFunc* = proc (handler_name: cstring, anObject: PGObject,
|
||||||
|
signal_name: cstring, signal_data: cstring,
|
||||||
|
connect_object: PGObject, after: gboolean,
|
||||||
|
user_data: gpointer){.cdecl.}
|
||||||
|
|
||||||
|
proc GLADE_TYPE_XML*(): GType
|
||||||
|
proc GLADE_XML*(obj: pointer): PGladeXML
|
||||||
|
proc GLADE_XML_CLASS*(klass: pointer): PGladeXMLClass
|
||||||
|
proc GLADE_IS_XML*(obj: pointer): gboolean
|
||||||
|
proc GLADE_IS_XML_CLASS*(klass: pointer): gboolean
|
||||||
|
proc GLADE_XML_GET_CLASS*(obj: pointer): PGladeXMLClass
|
||||||
|
proc glade_xml_get_type*(): GType{.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_xml_get_type".}
|
||||||
|
proc glade_xml_new*(fname: cstring, root: cstring, domain: cstring): PGladeXML{.
|
||||||
|
cdecl, dynlib: LibGladeLib, importc: "glade_xml_new".}
|
||||||
|
proc glade_xml_new_from_buffer*(buffer: cstring, size: int32, root: cstring,
|
||||||
|
domain: cstring): PGladeXML{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_new_from_buffer".}
|
||||||
|
proc glade_xml_construct*(self: PGladeXML, fname: cstring, root: cstring,
|
||||||
|
domain: cstring): gboolean{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_construct".}
|
||||||
|
proc glade_xml_signal_connect*(self: PGladeXML, handlername: cstring,
|
||||||
|
func: TGCallback){.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_xml_signal_connect".}
|
||||||
|
proc glade_xml_signal_connect_data*(self: PGladeXML, handlername: cstring,
|
||||||
|
func: TGCallback, user_data: gpointer){.
|
||||||
|
cdecl, dynlib: LibGladeLib, importc: "glade_xml_signal_connect_data".}
|
||||||
|
proc glade_xml_signal_autoconnect*(self: PGladeXML){.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_xml_signal_autoconnect".}
|
||||||
|
proc glade_xml_signal_connect_full*(self: PGladeXML, handler_name: cstring,
|
||||||
|
func: TGladeXMLConnectFunc,
|
||||||
|
user_data: gpointer){.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_signal_connect_full".}
|
||||||
|
proc glade_xml_signal_autoconnect_full*(self: PGladeXML,
|
||||||
|
func: TGladeXMLConnectFunc,
|
||||||
|
user_data: gpointer){.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_signal_autoconnect_full".}
|
||||||
|
proc glade_xml_get_widget*(self: PGladeXML, name: cstring): PGtkWidget{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_get_widget".}
|
||||||
|
proc glade_xml_get_widget_prefix*(self: PGladeXML, name: cstring): PGList{.
|
||||||
|
cdecl, dynlib: LibGladeLib, importc: "glade_xml_get_widget_prefix".}
|
||||||
|
proc glade_xml_relative_file*(self: PGladeXML, filename: cstring): cstring{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_xml_relative_file".}
|
||||||
|
proc glade_get_widget_name*(widget: PGtkWidget): cstring{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_get_widget_name".}
|
||||||
|
proc glade_get_widget_tree*(widget: PGtkWidget): PGladeXML{.cdecl,
|
||||||
|
dynlib: LibGladeLib, importc: "glade_get_widget_tree".}
|
||||||
|
type
|
||||||
|
PGladeXMLCustomWidgetHandler* = ptr TGladeXMLCustomWidgetHandler
|
||||||
|
TGladeXMLCustomWidgetHandler* = TGtkWidget
|
||||||
|
|
||||||
|
proc glade_set_custom_handler*(handler: TGladeXMLCustomWidgetHandler,
|
||||||
|
user_data: gpointer){.cdecl, dynlib: LibGladeLib,
|
||||||
|
importc: "glade_set_custom_handler".}
|
||||||
|
proc glade_gnome_init*() =
|
||||||
|
glade_init()
|
||||||
|
|
||||||
|
proc glade_bonobo_init*() =
|
||||||
|
glade_init()
|
||||||
|
|
||||||
|
proc glade_xml_new_with_domain*(fname: cstring, root: cstring, domain: cstring): PGladeXML =
|
||||||
|
result = glade_xml_new(fname, root, domain)
|
||||||
|
|
||||||
|
proc glade_xml_new_from_memory*(buffer: cstring, size: int32, root: cstring,
|
||||||
|
domain: cstring): PGladeXML =
|
||||||
|
result = glade_xml_new_from_buffer(buffer, size, root, domain)
|
||||||
|
|
||||||
|
proc GLADE_TYPE_XML*(): GType =
|
||||||
|
result = glade_xml_get_type()
|
||||||
|
|
||||||
|
proc GLADE_XML*(obj: pointer): PGladeXML =
|
||||||
|
result = cast[PGladeXML](G_TYPE_CHECK_INSTANCE_CAST(obj, GLADE_TYPE_XML()))
|
||||||
|
|
||||||
|
proc GLADE_XML_CLASS*(klass: pointer): PGladeXMLClass =
|
||||||
|
result = cast[PGladeXMLClass](G_TYPE_CHECK_CLASS_CAST(klass, GLADE_TYPE_XML()))
|
||||||
|
|
||||||
|
proc GLADE_IS_XML*(obj: pointer): gboolean =
|
||||||
|
result = G_TYPE_CHECK_INSTANCE_TYPE(obj, GLADE_TYPE_XML())
|
||||||
|
|
||||||
|
proc GLADE_IS_XML_CLASS*(klass: pointer): gboolean =
|
||||||
|
result = G_TYPE_CHECK_CLASS_TYPE(klass, GLADE_TYPE_XML())
|
||||||
|
|
||||||
|
proc GLADE_XML_GET_CLASS*(obj: pointer): PGladeXMLClass =
|
||||||
|
result = cast[PGladeXMLClass](G_TYPE_INSTANCE_GET_CLASS(obj, GLADE_TYPE_XML()))
|
||||||
1209
lib/base/gtk/pango.nim
Executable file
1209
lib/base/gtk/pango.nim
Executable file
File diff suppressed because it is too large
Load diff
46
lib/base/gtk/pangoutils.nim
Executable file
46
lib/base/gtk/pangoutils.nim
Executable file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import
|
||||||
|
glib2, pango
|
||||||
|
|
||||||
|
type
|
||||||
|
pint32* = ptr int32
|
||||||
|
|
||||||
|
proc pango_split_file_list*(str: cstring): PPchar{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_split_file_list".}
|
||||||
|
proc pango_trim_string*(str: cstring): cstring{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_trim_string".}
|
||||||
|
proc pango_read_line*(stream: TFile, str: PGString): gint{.cdecl,
|
||||||
|
dynlib: pangolib, importc: "pango_read_line".}
|
||||||
|
proc pango_skip_space*(pos: PPchar): gboolean{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_skip_space".}
|
||||||
|
proc pango_scan_word*(pos: PPchar, OutStr: PGString): gboolean{.cdecl,
|
||||||
|
dynlib: pangolib, importc: "pango_scan_word".}
|
||||||
|
proc pango_scan_string*(pos: PPchar, OutStr: PGString): gboolean{.cdecl,
|
||||||
|
dynlib: pangolib, importc: "pango_scan_string".}
|
||||||
|
proc pango_scan_int*(pos: PPchar, OutInt: pint32): gboolean{.cdecl,
|
||||||
|
dynlib: pangolib, importc: "pango_scan_int".}
|
||||||
|
when defined(PANGO_ENABLE_BACKEND):
|
||||||
|
proc pango_config_key_get(key: cstring): cstring{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_config_key_get".}
|
||||||
|
proc pango_lookup_aliases(fontname: cstring, families: PPPchar,
|
||||||
|
n_families: pint32){.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_lookup_aliases".}
|
||||||
|
proc pango_parse_style*(str: cstring, style: PPangoStyle, warn: gboolean): gboolean{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_parse_style".}
|
||||||
|
proc pango_parse_variant*(str: cstring, variant: PPangoVariant, warn: gboolean): gboolean{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_parse_variant".}
|
||||||
|
proc pango_parse_weight*(str: cstring, weight: PPangoWeight, warn: gboolean): gboolean{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_parse_weight".}
|
||||||
|
proc pango_parse_stretch*(str: cstring, stretch: PPangoStretch, warn: gboolean): gboolean{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_parse_stretch".}
|
||||||
|
when defined(PANGO_ENABLE_BACKEND):
|
||||||
|
proc pango_get_sysconf_subdirectory(): cstring{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_get_sysconf_subdirectory".}
|
||||||
|
proc pango_get_lib_subdirectory(): cstring{.cdecl, dynlib: pangolib,
|
||||||
|
importc: "pango_get_lib_subdirectory".}
|
||||||
|
proc pango_log2vis_get_embedding_levels*(str: Pgunichar, len: int32,
|
||||||
|
pbase_dir: PPangoDirection, embedding_level_list: Pguint8): gboolean{.cdecl,
|
||||||
|
dynlib: pangolib, importc: "pango_log2vis_get_embedding_levels".}
|
||||||
|
proc pango_get_mirror_char*(ch: gunichar, mirrored_ch: Pgunichar): gboolean{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_get_mirror_char".}
|
||||||
|
proc pango_language_get_sample_string*(language: PPangoLanguage): cstring{.
|
||||||
|
cdecl, dynlib: pangolib, importc: "pango_language_get_sample_string".}
|
||||||
124
lib/base/nregex.nim
Executable file
124
lib/base/nregex.nim
Executable file
|
|
@ -0,0 +1,124 @@
|
||||||
|
# new implementation of regular expressions
|
||||||
|
|
||||||
|
type
|
||||||
|
TRegexKind = enum
|
||||||
|
regNone,
|
||||||
|
regChar,
|
||||||
|
regSet,
|
||||||
|
regConc,
|
||||||
|
regAlt,
|
||||||
|
regStar,
|
||||||
|
regPlus,
|
||||||
|
regMN,
|
||||||
|
regNewline
|
||||||
|
|
||||||
|
TRegex = record
|
||||||
|
case kind: TRegexKind
|
||||||
|
of regChar: c: char
|
||||||
|
of regSet: s: ref set[char]
|
||||||
|
else: a, b: PRegEx
|
||||||
|
|
||||||
|
PRegEx* = ref TRegEx
|
||||||
|
|
||||||
|
TRegExFlag* = enum ## Flags concerning the semantics of regular expressions
|
||||||
|
reCaseInsensitive, ## case insensitive match
|
||||||
|
reStyleInsensitive ## style insensitive match
|
||||||
|
|
||||||
|
|
||||||
|
TRegExFlags* = set[TRegExFlag]
|
||||||
|
## Flags concerning the semantics of regular expressions
|
||||||
|
|
||||||
|
proc raiseRegex(msg: string) {.noreturn.} =
|
||||||
|
var e: ref Exception
|
||||||
|
new(e)
|
||||||
|
e.msg = msg
|
||||||
|
raise e
|
||||||
|
|
||||||
|
proc compileAux(i: int, s: string, r: PRegEx): int
|
||||||
|
|
||||||
|
proc compileBackslash(i: int, s: string, r: PRegEx): int =
|
||||||
|
var i = i
|
||||||
|
inc(i)
|
||||||
|
case s[i]
|
||||||
|
of 'A'..'Z':
|
||||||
|
of 'a'..'z':
|
||||||
|
of '0':
|
||||||
|
of '1'..'9':
|
||||||
|
|
||||||
|
else:
|
||||||
|
r.kind = regChar
|
||||||
|
r.c = s[i]
|
||||||
|
inc(i)
|
||||||
|
result = i
|
||||||
|
|
||||||
|
proc compileAtom(i: int, s: string, r: PRegEx): int =
|
||||||
|
var i = i
|
||||||
|
case s[i]
|
||||||
|
of '[':
|
||||||
|
inc(i)
|
||||||
|
var inverse = s[i] == '^'
|
||||||
|
if inverse: inc(i)
|
||||||
|
r.kind = regSet
|
||||||
|
new(r.s)
|
||||||
|
while true:
|
||||||
|
case s[i]
|
||||||
|
of '\\': i = compileBackslash(i, s, r)
|
||||||
|
of ']':
|
||||||
|
inc(i)
|
||||||
|
break
|
||||||
|
of '\0':
|
||||||
|
raiseRegex("']' expected")
|
||||||
|
elif s[i+1] == '-':
|
||||||
|
var x = s[i]
|
||||||
|
inc(i, 2)
|
||||||
|
var y = s[i]
|
||||||
|
inc(i)
|
||||||
|
r.s = r.s + {x..y}
|
||||||
|
else:
|
||||||
|
incl(r.s, s[i])
|
||||||
|
inc(i)
|
||||||
|
if inverse:
|
||||||
|
r.s = {'\0'..'\255'} - r.s
|
||||||
|
of '\\':
|
||||||
|
inc(i)
|
||||||
|
i = compileBackslash(i, s, r)
|
||||||
|
of '.':
|
||||||
|
r.kind = regAny
|
||||||
|
inc(i)
|
||||||
|
of '(':
|
||||||
|
inc(i)
|
||||||
|
i = compileAux(i, s, r)
|
||||||
|
if s[i] = ')': inc(i)
|
||||||
|
else: raiseRegex("')' expected")
|
||||||
|
of '\0': nil # do nothing
|
||||||
|
else:
|
||||||
|
r.kind = regChar
|
||||||
|
r.c = s[i]
|
||||||
|
inc(i)
|
||||||
|
result = i
|
||||||
|
|
||||||
|
proc compilePostfix(i: int, s: string, r: PRegEx): int =
|
||||||
|
var i = compileAtom(i, s, r)
|
||||||
|
var a: PRegEx
|
||||||
|
case s[i]
|
||||||
|
of '*':
|
||||||
|
of '+':
|
||||||
|
of '?':
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
proc compileAux(i: int, s: string, r: PRegEx): int =
|
||||||
|
var i = i
|
||||||
|
i = compileAtom(i, s, r)
|
||||||
|
|
||||||
|
while s[i] != '\0':
|
||||||
|
|
||||||
|
result = i
|
||||||
|
|
||||||
|
proc compile*(regex: string, flags: TRegExFlags = {}): PRegEx =
|
||||||
|
## Compiles the string `regex` that represents a regular expression into
|
||||||
|
## an internal data structure that can be used for matching.
|
||||||
|
new(result)
|
||||||
|
var i = compileAux(0, regex, result)
|
||||||
|
if i < len(regex)-1:
|
||||||
|
# not all characters used for the regular expression?
|
||||||
|
raiseRegEx("invalid regular expression")
|
||||||
296
lib/base/pcre.nim
Executable file
296
lib/base/pcre.nim
Executable file
|
|
@ -0,0 +1,296 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file was created by a complicated procedure which saved me a considerable
|
||||||
|
# amount of time: the pcre.h header was converted to modpcre.h by hand, so that
|
||||||
|
# h2pas could handle it. Then I used pas2mor to generate a Morpork binding.
|
||||||
|
# Unfortunately, I had to fix some things later on; thus don't do all this
|
||||||
|
# again! My manual changes will be lost!
|
||||||
|
|
||||||
|
# Converted by Pas2mor v1.37
|
||||||
|
#
|
||||||
|
# Automatically converted by H2Pas 0.99.16 from modpcre.h
|
||||||
|
# The following command line parameters were used:
|
||||||
|
# -D -c -l pcre.lib -T modpcre.h
|
||||||
|
|
||||||
|
{.compile: "pcre_all.c" .}
|
||||||
|
|
||||||
|
type
|
||||||
|
Pbyte = ptr byte
|
||||||
|
Pchar = CString
|
||||||
|
PPchar = ptr PChar
|
||||||
|
Pint = ptr cint
|
||||||
|
Ppcre* = ptr TPcre
|
||||||
|
Ppcre_callout_block = ptr tpcre_callout_block
|
||||||
|
Ppcre_extra = ptr Tpcre_extra
|
||||||
|
|
||||||
|
#************************************************
|
||||||
|
#* Perl-Compatible Regular Expressions *
|
||||||
|
#************************************************
|
||||||
|
#
|
||||||
|
# Modified by Andreas Rumpf for h2pas.
|
||||||
|
|
||||||
|
# In its original form, this is the .in file that is transformed by
|
||||||
|
# "configure" into pcre.h.
|
||||||
|
#
|
||||||
|
# Copyright (c) 1997-2005 University of Cambridge
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# * Neither the name of the University of Cambridge nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The file pcre.h is build by "configure". Do not edit it; instead
|
||||||
|
# make changes to pcre.in.
|
||||||
|
|
||||||
|
const
|
||||||
|
PCRE_MAJOR* = 6
|
||||||
|
PCRE_MINOR* = 3
|
||||||
|
PCRE_DATE* = "2005/11/29"
|
||||||
|
# Options
|
||||||
|
PCRE_CASELESS* = 0x00000001
|
||||||
|
PCRE_MULTILINE* = 0x00000002
|
||||||
|
PCRE_DOTALL* = 0x00000004
|
||||||
|
PCRE_EXTENDED* = 0x00000008
|
||||||
|
PCRE_ANCHORED* = 0x00000010
|
||||||
|
PCRE_DOLLAR_ENDONLY* = 0x00000020
|
||||||
|
PCRE_EXTRA* = 0x00000040
|
||||||
|
PCRE_NOTBOL* = 0x00000080
|
||||||
|
PCRE_NOTEOL* = 0x00000100
|
||||||
|
PCRE_UNGREEDY* = 0x00000200
|
||||||
|
PCRE_NOTEMPTY* = 0x00000400
|
||||||
|
PCRE_UTF8* = 0x00000800
|
||||||
|
PCRE_NO_AUTO_CAPTURE* = 0x00001000
|
||||||
|
PCRE_NO_UTF8_CHECK* = 0x00002000
|
||||||
|
PCRE_AUTO_CALLOUT* = 0x00004000
|
||||||
|
PCRE_PARTIAL* = 0x00008000
|
||||||
|
PCRE_DFA_SHORTEST* = 0x00010000
|
||||||
|
PCRE_DFA_RESTART* = 0x00020000
|
||||||
|
PCRE_FIRSTLINE* = 0x00040000
|
||||||
|
# Exec-time and get/set-time error codes
|
||||||
|
PCRE_ERROR_NOMATCH* = -(1)
|
||||||
|
PCRE_ERROR_NULL* = -(2)
|
||||||
|
PCRE_ERROR_BADOPTION* = -(3)
|
||||||
|
PCRE_ERROR_BADMAGIC* = -(4)
|
||||||
|
PCRE_ERROR_UNKNOWN_NODE* = -(5)
|
||||||
|
PCRE_ERROR_NOMEMORY* = -(6)
|
||||||
|
PCRE_ERROR_NOSUBSTRING* = -(7)
|
||||||
|
PCRE_ERROR_MATCHLIMIT* = -(8)
|
||||||
|
# Never used by PCRE itself
|
||||||
|
PCRE_ERROR_CALLOUT* = -(9)
|
||||||
|
PCRE_ERROR_BADUTF8* = -(10)
|
||||||
|
PCRE_ERROR_BADUTF8_OFFSET* = -(11)
|
||||||
|
PCRE_ERROR_PARTIAL* = -(12)
|
||||||
|
PCRE_ERROR_BADPARTIAL* = -(13)
|
||||||
|
PCRE_ERROR_INTERNAL* = -(14)
|
||||||
|
PCRE_ERROR_BADCOUNT* = -(15)
|
||||||
|
PCRE_ERROR_DFA_UITEM* = -(16)
|
||||||
|
PCRE_ERROR_DFA_UCOND* = -(17)
|
||||||
|
PCRE_ERROR_DFA_UMLIMIT* = -(18)
|
||||||
|
PCRE_ERROR_DFA_WSSIZE* = -(19)
|
||||||
|
PCRE_ERROR_DFA_RECURSE* = -(20)
|
||||||
|
# Request types for pcre_fullinfo()
|
||||||
|
PCRE_INFO_OPTIONS* = 0
|
||||||
|
PCRE_INFO_SIZE* = 1
|
||||||
|
PCRE_INFO_CAPTURECOUNT* = 2
|
||||||
|
PCRE_INFO_BACKREFMAX* = 3
|
||||||
|
PCRE_INFO_FIRSTBYTE* = 4
|
||||||
|
# For backwards compatibility
|
||||||
|
PCRE_INFO_FIRSTCHAR* = 4
|
||||||
|
PCRE_INFO_FIRSTTABLE* = 5
|
||||||
|
PCRE_INFO_LASTLITERAL* = 6
|
||||||
|
PCRE_INFO_NAMEENTRYSIZE* = 7
|
||||||
|
PCRE_INFO_NAMECOUNT* = 8
|
||||||
|
PCRE_INFO_NAMETABLE* = 9
|
||||||
|
PCRE_INFO_STUDYSIZE* = 10
|
||||||
|
PCRE_INFO_DEFAULT_TABLES* = 11
|
||||||
|
# Request types for pcre_config()
|
||||||
|
PCRE_CONFIG_UTF8* = 0
|
||||||
|
PCRE_CONFIG_NEWLINE* = 1
|
||||||
|
PCRE_CONFIG_LINK_SIZE* = 2
|
||||||
|
PCRE_CONFIG_POSIX_MALLOC_THRESHOLD* = 3
|
||||||
|
PCRE_CONFIG_MATCH_LIMIT* = 4
|
||||||
|
PCRE_CONFIG_STACKRECURSE* = 5
|
||||||
|
PCRE_CONFIG_UNICODE_PROPERTIES* = 6
|
||||||
|
# Bit flags for the pcre_extra structure
|
||||||
|
PCRE_EXTRA_STUDY_DATA* = 0x0001
|
||||||
|
PCRE_EXTRA_MATCH_LIMIT* = 0x0002
|
||||||
|
PCRE_EXTRA_CALLOUT_DATA* = 0x0004
|
||||||
|
PCRE_EXTRA_TABLES* = 0x0008
|
||||||
|
# Types
|
||||||
|
|
||||||
|
type
|
||||||
|
TPcre = record
|
||||||
|
#undefined structure
|
||||||
|
|
||||||
|
|
||||||
|
# The structure for passing additional data to pcre_exec(). This is defined
|
||||||
|
# in such as way as to be extensible. Always add new fields at the end,
|
||||||
|
# in order to remain compatible.
|
||||||
|
# Bits for which fields are set
|
||||||
|
# Opaque data from pcre_study()
|
||||||
|
# Maximum number of calls to match()
|
||||||
|
# Data passed back in callouts
|
||||||
|
# Const before type ignored
|
||||||
|
# Pointer to character tables
|
||||||
|
Tpcre_extra* = record
|
||||||
|
flags: cuint
|
||||||
|
study_data: pointer
|
||||||
|
match_limit: cuint
|
||||||
|
callout_data: pointer
|
||||||
|
tables: ptr byte
|
||||||
|
|
||||||
|
# The structure for passing out data via the pcre_callout_function. We use a
|
||||||
|
# structure so that new fields can be added on the end in future versions,
|
||||||
|
# without changing the API of the function, thereby allowing old clients to
|
||||||
|
# work without modification.
|
||||||
|
# Identifies version of block
|
||||||
|
# ------------------------ Version 0 -------------------------------
|
||||||
|
# Number compiled into pattern
|
||||||
|
# The offset vector
|
||||||
|
# Const before type ignored
|
||||||
|
# The subject being matched
|
||||||
|
# The length of the subject
|
||||||
|
# Offset to start of this match attempt
|
||||||
|
# Where we currently are in the subject
|
||||||
|
# Max current capture
|
||||||
|
# Most recently closed capture
|
||||||
|
# Data passed in with the call
|
||||||
|
# ------------------- Added for Version 1 --------------------------
|
||||||
|
# Offset to next item in the pattern
|
||||||
|
# Length of next item in the pattern
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
TPcre_callout_block* = record
|
||||||
|
version: cint
|
||||||
|
callout_number: cint
|
||||||
|
offset_vector: ptr cint
|
||||||
|
subject: ptr char
|
||||||
|
subject_length: cint
|
||||||
|
start_match: cint
|
||||||
|
current_position: cint
|
||||||
|
capture_top: cint
|
||||||
|
capture_last: cint
|
||||||
|
callout_data: pointer
|
||||||
|
pattern_position: cint
|
||||||
|
next_item_length: cint
|
||||||
|
|
||||||
|
# Exported PCRE functions
|
||||||
|
|
||||||
|
proc pcre_compile*(para1: Pchar, para2: cint, para3: ptr Pchar,
|
||||||
|
para4: Pint, para5: Pbyte): Ppcre {.
|
||||||
|
importc: "pcre_compile", noconv.}
|
||||||
|
|
||||||
|
proc pcre_compile2*(para1: Pchar, para2: cint, para3: Pint, para4: PPchar,
|
||||||
|
para5: Pint, para6: Pbyte): Ppcre {.
|
||||||
|
importc: "pcre_compile2", noconv.}
|
||||||
|
|
||||||
|
proc pcre_config*(para1: cint, para2: pointer): cint {.
|
||||||
|
importc: "pcre_config", noconv.}
|
||||||
|
|
||||||
|
proc pcre_copy_named_substring*(para1: Ppcre, para2: Pchar, para3: Pint,
|
||||||
|
para4: cint, para5: Pchar, para6: Pchar,
|
||||||
|
para7: cint): cint {.
|
||||||
|
importc: "pcre_copy_named_substring", noconv.}
|
||||||
|
|
||||||
|
proc pcre_copy_substring*(para1: Pchar, para2: Pint, para3: cint, para4: cint,
|
||||||
|
para5: Pchar, para6: cint): cint {.
|
||||||
|
importc: "pcre_copy_substring", noconv.}
|
||||||
|
|
||||||
|
proc pcre_dfa_exec*(para1: Ppcre, para2: Ppcre_extra, para3: Pchar,
|
||||||
|
para4: cint, para5: cint, para6: cint, para7: Pint,
|
||||||
|
para8: cint, para9: Pint, para10: cint): cint {.
|
||||||
|
importc: "pcre_dfa_exec", noconv.}
|
||||||
|
|
||||||
|
proc pcre_exec*(para1: Ppcre, para2: Ppcre_extra, para3: Pchar,
|
||||||
|
para4: cint, para5: cint, para6: cint, para7: Pint,
|
||||||
|
para8: cint): cint {.importc: "pcre_exec", noconv.}
|
||||||
|
|
||||||
|
proc pcre_free_substring*(para1: Pchar) {.
|
||||||
|
importc: "pcre_free_substring", noconv.}
|
||||||
|
|
||||||
|
proc pcre_free_substring_list*(para1: PPchar) {.
|
||||||
|
importc: "pcre_free_substring_list", noconv.}
|
||||||
|
|
||||||
|
proc pcre_fullinfo*(para1: Ppcre, para2: Ppcre_extra, para3: cint,
|
||||||
|
para4: pointer): cint {.importc: "pcre_fullinfo", noconv.}
|
||||||
|
|
||||||
|
proc pcre_get_named_substring*(para1: Ppcre, para2: Pchar, para3: Pint,
|
||||||
|
para4: cint, para5: Pchar, para6: PPchar): cint {.
|
||||||
|
importc: "pcre_get_named_substring", noconv.}
|
||||||
|
|
||||||
|
proc pcre_get_stringnumber*(para1: Ppcre, para2: Pchar): cint {.
|
||||||
|
importc: "pcre_get_stringnumber", noconv.}
|
||||||
|
|
||||||
|
proc pcre_get_substring*(para1: Pchar, para2: Pint, para3: cint,
|
||||||
|
para4: cint, para5: PPchar): cint {.
|
||||||
|
importc: "pcre_get_substring", noconv.}
|
||||||
|
|
||||||
|
proc pcre_get_substring_list*(para1: Pchar, para2: Pint, para3: cint,
|
||||||
|
para4: ptr PPchar): cint {.
|
||||||
|
importc: "pcre_get_substring_list", noconv.}
|
||||||
|
|
||||||
|
proc pcre_info*(para1: Ppcre, para2: Pint, para3: Pint): cint {.
|
||||||
|
importc: "pcre_info", noconv.}
|
||||||
|
|
||||||
|
proc pcre_maketables*: ptr byte {.
|
||||||
|
importc: "pcre_maketables", noconv.}
|
||||||
|
|
||||||
|
proc pcre_refcount*(para1: Ppcre, para2: cint): cint {.
|
||||||
|
importc: "pcre_refcount", noconv.}
|
||||||
|
|
||||||
|
proc pcre_study*(para1: Ppcre, para2: cint,
|
||||||
|
para3: ptr CString): Ppcre_extra {.importc, noconv.}
|
||||||
|
|
||||||
|
proc pcre_version*: CString {.importc: "pcre_version", noconv.}
|
||||||
|
|
||||||
|
# Indirection for store get and free functions. These can be set to
|
||||||
|
# alternative malloc/free functions if required. Special ones are used in the
|
||||||
|
# non-recursive case for "frames". There is also an optional callout function
|
||||||
|
# that is triggered by the (?) regex item.
|
||||||
|
#
|
||||||
|
|
||||||
|
# we use Nimrod's memory manager (but not GC!) for these functions:
|
||||||
|
var
|
||||||
|
pcre_malloc {.importc: "pcre_malloc".}: proc (para1: int): pointer {.noconv.}
|
||||||
|
pcre_free {.importc: "pcre_free".}: proc (para1: pointer) {.noconv.}
|
||||||
|
pcre_stack_malloc {.importc: "pcre_stack_malloc".}:
|
||||||
|
proc (para1: int): pointer {.noconv.}
|
||||||
|
pcre_stack_free {.importc: "pcre_stack_free".}:
|
||||||
|
proc (para1: pointer) {.noconv.}
|
||||||
|
pcre_callout {.importc: "pcre_callout".}:
|
||||||
|
proc (para1: Ppcre_callout_block): cint {.noconv.}
|
||||||
|
|
||||||
|
pcre_malloc = system.alloc
|
||||||
|
pcre_free = system.dealloc
|
||||||
|
pcre_stack_malloc = system.alloc
|
||||||
|
pcre_stack_free = system.dealloc
|
||||||
|
pcre_callout = nil
|
||||||
30072
lib/base/pcre_all.c
Executable file
30072
lib/base/pcre_all.c
Executable file
File diff suppressed because it is too large
Load diff
114
lib/base/regexprs.nim
Executable file
114
lib/base/regexprs.nim
Executable file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Regular expression support for Nimrod.
|
||||||
|
## Currently this module is implemented by providing a wrapper around the
|
||||||
|
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
|
||||||
|
## C library. This means that your application will depend on the PRCE
|
||||||
|
## library's licence when using this module, which should not be a problem
|
||||||
|
## though.
|
||||||
|
## PRCE's licence follows:
|
||||||
|
##
|
||||||
|
## .. include:: ../doc/regexprs.txt
|
||||||
|
##
|
||||||
|
|
||||||
|
# This is not just a convenient wrapper for the pcre library; the
|
||||||
|
# API will stay the same if the implementation should change.
|
||||||
|
|
||||||
|
import
|
||||||
|
pcre, strutils
|
||||||
|
|
||||||
|
type
|
||||||
|
EInvalidRegEx* = object of EInvalidValue
|
||||||
|
## is raised if the pattern is no valid regular expression.
|
||||||
|
|
||||||
|
const
|
||||||
|
MaxSubpatterns* = 10
|
||||||
|
## defines the maximum number of subpatterns that can be captured.
|
||||||
|
## More subpatterns cannot be captured!
|
||||||
|
|
||||||
|
proc match*(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): bool
|
||||||
|
## returns ``true`` if ``s`` matches the ``pattern[start..]`` and
|
||||||
|
## the captured substrings in the array ``substrs``. If it does not
|
||||||
|
## match, nothing is written into ``substrs`` and ``false`` is
|
||||||
|
## returned.
|
||||||
|
|
||||||
|
proc match*(s, pattern: string, start: int = 0): bool
|
||||||
|
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
|
||||||
|
|
||||||
|
proc matchLen*(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): int
|
||||||
|
## the same as ``match``, but it returns the length of the match,
|
||||||
|
## if there is no match, -1 is returned. Note that a match length
|
||||||
|
## of zero can happen.
|
||||||
|
|
||||||
|
proc find*(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): bool
|
||||||
|
## returns ``true`` if ``pattern`` occurs in ``s`` and the captured
|
||||||
|
## substrings in the array ``substrs``. If it does not match, nothing
|
||||||
|
## is written into ``substrs``.
|
||||||
|
proc find*(s, pattern: string, start: int = 0): bool
|
||||||
|
## returns ``true`` if ``pattern`` occurs in ``s``.
|
||||||
|
|
||||||
|
|
||||||
|
proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||||
|
var
|
||||||
|
msg: CString
|
||||||
|
offset: cint
|
||||||
|
com = pcreCompile(pattern, flags, addr(msg), addr(offset), nil)
|
||||||
|
if com == nil:
|
||||||
|
var e: ref EInvalidRegEx
|
||||||
|
new(e)
|
||||||
|
e.msg = $msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n"
|
||||||
|
raise e
|
||||||
|
return com
|
||||||
|
|
||||||
|
proc matchOrFind(s: string, pattern: PPcre, substrs: var openarray[string],
|
||||||
|
start: cint): cint =
|
||||||
|
var
|
||||||
|
rawMatches: array [0..maxSubpatterns * 3 - 1, cint]
|
||||||
|
res = int(pcreExec(pattern, nil, s, length(s), start, 0,
|
||||||
|
cast[pint](addr(rawMatches)), maxSubpatterns * 3))
|
||||||
|
dealloc(pattern)
|
||||||
|
if res < 0: return res
|
||||||
|
for i in 0..res-1:
|
||||||
|
var
|
||||||
|
a = rawMatches[i * 3]
|
||||||
|
b = rawMatches[i * 3 + 1]
|
||||||
|
if a >= 0: substrs[i] = copy(s, a, b)
|
||||||
|
else: substrs[i] = ""
|
||||||
|
return res
|
||||||
|
|
||||||
|
proc matchOrFind(s: string, pattern: PPcre, start: cint): cint =
|
||||||
|
var
|
||||||
|
rawMatches: array [0..maxSubpatterns * 3 - 1, cint]
|
||||||
|
res = pcreExec(pattern, nil, s, length(s), start, 0,
|
||||||
|
cast[pint](addr(rawMatches)), maxSubpatterns * 3)
|
||||||
|
dealloc(pattern)
|
||||||
|
return res
|
||||||
|
|
||||||
|
proc match(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): bool =
|
||||||
|
return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED),
|
||||||
|
substrs, start) >= 0
|
||||||
|
|
||||||
|
proc matchLen(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): int =
|
||||||
|
return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED), substrs, start)
|
||||||
|
|
||||||
|
proc find(s, pattern: string, substrs: var openarray[string],
|
||||||
|
start: int = 0): bool =
|
||||||
|
return matchOrFind(s, rawCompile(pattern, 0), substrs, start) >= 0
|
||||||
|
|
||||||
|
proc match(s, pattern: string, start: int = 0): bool =
|
||||||
|
return matchOrFind(s, rawCompile(pattern, PCRE_ANCHORED), start) >= 0
|
||||||
|
|
||||||
|
proc find(s, pattern: string, start: int = 0): bool =
|
||||||
|
return matchOrFind(s, rawCompile(pattern, 0), start) >= 0
|
||||||
20
lib/cntbits.nim
Executable file
20
lib/cntbits.nim
Executable file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
proc population16(a: int): int {.inline.} =
|
||||||
|
var x = a
|
||||||
|
x = ((x and 0xAAAA) shr 1) + (x and 0x5555)
|
||||||
|
x = ((x and 0xCCCC) shr 2) + (x and 0x3333)
|
||||||
|
x = ((x and 0xF0F0) shr 4) + (x and 0x0F0F)
|
||||||
|
x = ((x and 0xFF00) shr 8) + (x and 0x00FF)
|
||||||
|
return x
|
||||||
|
|
||||||
|
proc countBits(n: int32): int =
|
||||||
|
result = population16(n and 0xffff) + population16(n shr 16)
|
||||||
108
lib/complex.nim
Executable file
108
lib/complex.nim
Executable file
|
|
@ -0,0 +1,108 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## This module implements complex numbers.
|
||||||
|
|
||||||
|
{.push checks:off, line_dir:off, stack_trace:off, debugger:off.}
|
||||||
|
# the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
import
|
||||||
|
math
|
||||||
|
|
||||||
|
type
|
||||||
|
TComplex* = record ## a complex number, consisting of a real and an
|
||||||
|
## imaginary part
|
||||||
|
re*: float ## real part of the complex number
|
||||||
|
im*: float ## imarginary part of the complex number
|
||||||
|
|
||||||
|
proc `==` *(x, y: TComplex): bool =
|
||||||
|
## Compare two complex numbers `x` and `y` for equality.
|
||||||
|
result = x.re == y.re and x.im == y.im
|
||||||
|
|
||||||
|
proc `+` *(x, y: TComplex): TComplex =
|
||||||
|
## Add two complex numbers.
|
||||||
|
result.re = x.re + y.re
|
||||||
|
result.im = x.im + y.im
|
||||||
|
|
||||||
|
proc `-` *(x, y: TComplex): TComplex =
|
||||||
|
## Subtract two complex numbers.
|
||||||
|
result.re = x.re - y.re
|
||||||
|
result.im = x.im - y.im
|
||||||
|
|
||||||
|
proc `-` *(z: TComplex): TComplex =
|
||||||
|
## Unary minus for complex numbers.
|
||||||
|
result.re = -z.re
|
||||||
|
result.im = -z.im
|
||||||
|
|
||||||
|
proc `/` *(x, y: TComplex): TComplex =
|
||||||
|
## Divide `x` by `y`.
|
||||||
|
var
|
||||||
|
r, den: float
|
||||||
|
if abs(y.re) < abs(y.im):
|
||||||
|
r = y.re / y.im
|
||||||
|
den = y.im + r * y.re
|
||||||
|
result.re = (x.re * r + x.im) / den
|
||||||
|
result.im = (x.im * r - x.re) / den
|
||||||
|
else:
|
||||||
|
r = y.im / y.re
|
||||||
|
den = y.re + r * y.im
|
||||||
|
result.re = (x.re + r * x.im) / den
|
||||||
|
result.im = (x.im - r * x.re) / den
|
||||||
|
|
||||||
|
proc `*` *(x, y: TComplex): TComplex =
|
||||||
|
## Multiply `x` with `y`.
|
||||||
|
result.re = x.re * y.re - x.im * y.im
|
||||||
|
result.im = x.im * y.re + x.re * y.im
|
||||||
|
|
||||||
|
proc abs*(z: TComplex): float =
|
||||||
|
## Return the distance from (0,0) to `z`.
|
||||||
|
|
||||||
|
# optimized by checking special cases (sqrt is expensive)
|
||||||
|
var x, y, temp: float
|
||||||
|
|
||||||
|
x = abs(z.re)
|
||||||
|
y = abs(z.im)
|
||||||
|
if x == 0.0:
|
||||||
|
result = y
|
||||||
|
elif y == 0.0:
|
||||||
|
result = x
|
||||||
|
elif x > y:
|
||||||
|
temp = y / x
|
||||||
|
result = x * sqrt(1.0 + temp * temp)
|
||||||
|
else:
|
||||||
|
temp = x / y
|
||||||
|
result = y * sqrt(1.0 + temp * temp)
|
||||||
|
|
||||||
|
proc sqrt*(z: TComplex): TComplex =
|
||||||
|
## Square root for a complex number `z`.
|
||||||
|
var x, y, w, r: float
|
||||||
|
|
||||||
|
if z.re == 0.0 and z.im == 0.0:
|
||||||
|
result = z
|
||||||
|
else:
|
||||||
|
x = abs(z.re)
|
||||||
|
y = abs(z.im)
|
||||||
|
if x >= y:
|
||||||
|
r = y / x
|
||||||
|
w = sqrt(x) * sqrt(0.5 * (1.0 + sqrt(1.0 + r * r)))
|
||||||
|
else:
|
||||||
|
r = x / y
|
||||||
|
w = sqrt(y) * sqrt(0.5 * (r + sqrt(1.0 + r * r)))
|
||||||
|
if z.re >= 0.0:
|
||||||
|
result.re = w
|
||||||
|
result.im = z.im / (w * 2)
|
||||||
|
else:
|
||||||
|
if z.im >= 0.0: result.im = w
|
||||||
|
else: result.im = -w
|
||||||
|
result.re = z.im / (c.im + c.im)
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
29
lib/copying.txt
Executable file
29
lib/copying.txt
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
=======================================================
|
||||||
|
The Nimrod Runtime Library
|
||||||
|
Copyright (C) 2004-2007 Andreas Rumpf
|
||||||
|
=======================================================
|
||||||
|
|
||||||
|
This is the file copying.txt, it applies to the Nimrod Run-Time Library
|
||||||
|
(lib) and base packages (base) distributed by members of the Nimrod
|
||||||
|
Development Team.
|
||||||
|
|
||||||
|
The source code of the Nimrod Runtime Libraries and packages are
|
||||||
|
distributed under the Library GNU General Public License
|
||||||
|
(see the file lgpl.txt) with the following modification:
|
||||||
|
|
||||||
|
As a special exception, the copyright holders of this library give you
|
||||||
|
permission to link this library with independent modules to produce an
|
||||||
|
executable, regardless of the license terms of these independent modules,
|
||||||
|
and to copy and distribute the resulting executable under terms of your choice,
|
||||||
|
provided that you also meet, for each linked independent module, the terms
|
||||||
|
and conditions of the license of that module. An independent module is a module
|
||||||
|
which is not derived from or based on this library. If you modify this
|
||||||
|
library, you may extend this exception to your version of the library, but
|
||||||
|
you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
exception statement from your version.
|
||||||
|
|
||||||
|
If you didn't receive a copy of the file lgpl.txt, contact:
|
||||||
|
Free Software Foundation
|
||||||
|
675 Mass Ave
|
||||||
|
Cambridge, MA 02139
|
||||||
|
USA
|
||||||
499
lib/debugger.nim
Executable file
499
lib/debugger.nim
Executable file
|
|
@ -0,0 +1,499 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# This file implements the embedded debugger that can be linked
|
||||||
|
# with the application. We should not use dynamic memory here as that
|
||||||
|
# would interfere with the GC and trigger ON/OFF errors if the
|
||||||
|
# user program corrupts memory. Unfortunately, for dispaying
|
||||||
|
# variables we use the system.repr() proc which uses Nimrod
|
||||||
|
# strings and thus allocates memory from the heap. Pity, but
|
||||||
|
# I do not want to implement repr() twice. We also cannot deactivate
|
||||||
|
# the GC here as that might run out of memory too quickly...
|
||||||
|
|
||||||
|
type
|
||||||
|
TDbgState = enum
|
||||||
|
dbOff, # debugger is turned off
|
||||||
|
dbStepInto, # debugger is in tracing mode
|
||||||
|
dbStepOver,
|
||||||
|
dbSkipCurrent,
|
||||||
|
dbQuiting, # debugger wants to quit
|
||||||
|
dbBreakpoints # debugger is only interested in breakpoints
|
||||||
|
|
||||||
|
TDbgBreakpoint = record
|
||||||
|
low, high: int # range from low to high; if disabled
|
||||||
|
# both low and high are set to their negative values
|
||||||
|
# this makes the check faster and safes memory
|
||||||
|
filename: string
|
||||||
|
name: string # name of breakpoint
|
||||||
|
|
||||||
|
TVarSlot {.compilerproc.} = record # variable slots used for debugger:
|
||||||
|
address: pointer
|
||||||
|
typ: PNimType
|
||||||
|
name: cstring # for globals this is "module.name"
|
||||||
|
|
||||||
|
PExtendedFrame = ptr TExtendedFrame
|
||||||
|
TExtendedFrame = record # If the debugger is enabled the compiler provides
|
||||||
|
# an extended frame. Of course only slots that are
|
||||||
|
# needed are allocated and not 10_000, except for
|
||||||
|
# the global data description.
|
||||||
|
f: TFrame
|
||||||
|
slots: array[0..10_000, TVarSlot]
|
||||||
|
|
||||||
|
var
|
||||||
|
dbgInSignal: bool # wether the debugger is in the signal handler
|
||||||
|
dbgIn: TFile # debugger input stream
|
||||||
|
dbgUser: string = "s" # buffer for user input; first command is ``step_into``
|
||||||
|
# needs to be global cause we store the last command
|
||||||
|
# in it
|
||||||
|
dbgState: TDbgState = dbStepInto # state of debugger
|
||||||
|
dbgBP: array[0..127, TDbgBreakpoint] # breakpoints
|
||||||
|
dbgBPlen: int = 0
|
||||||
|
|
||||||
|
dbgSkipToFrame: PFrame # frame to be skipped to
|
||||||
|
|
||||||
|
dbgGlobalData: TExtendedFrame # this reserves much space, but
|
||||||
|
# for now it is the most practical way
|
||||||
|
|
||||||
|
maxDisplayRecDepth: int = 5 # do not display too much data!
|
||||||
|
|
||||||
|
proc findBreakpoint(name: string): int =
|
||||||
|
# returns -1 if not found
|
||||||
|
for i in countdown(dbgBPlen-1, 0):
|
||||||
|
if name == dbgBP[i].name: return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc ListBreakPoints() =
|
||||||
|
write(stdout, "*** emdb| Breakpoints:\n")
|
||||||
|
for i in 0 .. dbgBPlen-1:
|
||||||
|
write(stdout, dbgBP[i].name & ": " & $abs(dbgBP[i].low) & ".." &
|
||||||
|
$abs(dbgBP[i].high) & dbgBP[i].filename)
|
||||||
|
if dbgBP[i].low < 0:
|
||||||
|
write(stdout, " [disabled]\n")
|
||||||
|
else:
|
||||||
|
write(stdout, "\n")
|
||||||
|
write(stdout, "***\n")
|
||||||
|
|
||||||
|
proc openAppend(filename: string): TFile =
|
||||||
|
if openFile(result, filename, fmAppend):
|
||||||
|
write(result, "----------------------------------------\n")
|
||||||
|
|
||||||
|
proc dbgRepr(p: pointer, typ: PNimType): string =
|
||||||
|
var
|
||||||
|
cl: TReprClosure
|
||||||
|
initReprClosure(cl)
|
||||||
|
cl.recDepth = maxDisplayRecDepth
|
||||||
|
# locks for the GC turned out to be a bad idea...
|
||||||
|
# inc(recGcLock)
|
||||||
|
result = ""
|
||||||
|
reprAux(result, p, typ, cl)
|
||||||
|
# dec(recGcLock)
|
||||||
|
deinitReprClosure(cl)
|
||||||
|
|
||||||
|
proc writeVariable(stream: TFile, slot: TVarSlot) =
|
||||||
|
write(stream, slot.name)
|
||||||
|
write(stream, " = ")
|
||||||
|
writeln(stream, dbgRepr(slot.address, slot.typ))
|
||||||
|
|
||||||
|
proc ListFrame(stream: TFile, f: PExtendedFrame) =
|
||||||
|
write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n")
|
||||||
|
for i in 0 .. f.f.len-1:
|
||||||
|
writeVariable(stream, f.slots[i])
|
||||||
|
write(stream, "***\n")
|
||||||
|
|
||||||
|
proc ListVariables(stream: TFile, f: PExtendedFrame) =
|
||||||
|
write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n")
|
||||||
|
for i in 0 .. f.f.len-1:
|
||||||
|
writeln(stream, f.slots[i].name)
|
||||||
|
write(stream, "***\n")
|
||||||
|
|
||||||
|
proc debugOut(msg: cstring) =
|
||||||
|
# the *** *** markers are for easy recognition of debugger
|
||||||
|
# output for external frontends.
|
||||||
|
write(stdout, "*** emdb| ")
|
||||||
|
write(stdout, msg)
|
||||||
|
write(stdout, "***\n")
|
||||||
|
|
||||||
|
proc dbgFatal(msg: cstring) =
|
||||||
|
debugOut(msg)
|
||||||
|
dbgAborting = True # the debugger wants to abort
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
proc findVariable(frame: PExtendedFrame, varname: cstring): int =
|
||||||
|
for i in 0 .. frame.f.len - 1:
|
||||||
|
if c_strcmp(frame.slots[i].name, varname) == 0: return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
|
||||||
|
if dbgFramePointer != nil:
|
||||||
|
write(stdout, "*** emdb| now in proc: ")
|
||||||
|
write(stdout, dbgFramePointer.procname)
|
||||||
|
write(stdout, " ***\n")
|
||||||
|
else:
|
||||||
|
write(stdout, "*** emdb| (procedure name not available) ***\n")
|
||||||
|
|
||||||
|
proc dbgShowExecutionPoint() =
|
||||||
|
write(stdout, "*** emdb| " & $framePtr.filename & "(" & $framePtr.line &
|
||||||
|
") " & $framePtr.procname & " ***\n")
|
||||||
|
|
||||||
|
when defined(windows) or defined(dos) or defined(os2):
|
||||||
|
{.define: FileSystemCaseInsensitive.}
|
||||||
|
|
||||||
|
proc fileMatches(c, bp: cstring): bool =
|
||||||
|
# bp = breakpoint filename
|
||||||
|
# c = current filename
|
||||||
|
# we consider it a match if bp is a suffix of c
|
||||||
|
# and the character for the suffix does not exist or
|
||||||
|
# is one of: \ / :
|
||||||
|
# depending on the OS case does not matter!
|
||||||
|
var blen: int = c_strlen(bp)
|
||||||
|
var clen: int = c_strlen(c)
|
||||||
|
if blen > clen: return false
|
||||||
|
# check for \ / :
|
||||||
|
if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}:
|
||||||
|
return false
|
||||||
|
var i = 0
|
||||||
|
while i < blen:
|
||||||
|
var x, y: char
|
||||||
|
x = bp[i]
|
||||||
|
y = c[i+clen-blen]
|
||||||
|
when defined(FileSystemCaseInsensitive):
|
||||||
|
if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
|
||||||
|
if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
|
||||||
|
if x != y: return false
|
||||||
|
inc(i)
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc dbgBreakpointReached(line: int): int =
|
||||||
|
for i in 0..dbgBPlen-1:
|
||||||
|
if line >= dbgBP[i].low and line <= dbgBP[i].high and
|
||||||
|
fileMatches(framePtr.filename, dbgBP[i].filename): return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc scanAndAppendWord(src: string, a: var string, start: int): int =
|
||||||
|
result = start
|
||||||
|
# skip whitespace:
|
||||||
|
while src[result] in {'\t', ' '}: inc(result)
|
||||||
|
while True:
|
||||||
|
case src[result]
|
||||||
|
of 'a'..'z', '0'..'9': add(a, src[result])
|
||||||
|
of '_': nil # just skip it
|
||||||
|
of 'A'..'Z': add(a, chr(ord(src[result]) - ord('A') + ord('a')))
|
||||||
|
else: break
|
||||||
|
inc(result)
|
||||||
|
|
||||||
|
proc scanWord(src: string, a: var string, start: int): int =
|
||||||
|
a = ""
|
||||||
|
result = scanAndAppendWord(src, a, start)
|
||||||
|
|
||||||
|
proc scanFilename(src: string, a: var string, start: int): int =
|
||||||
|
result = start
|
||||||
|
a = ""
|
||||||
|
# skip whitespace:
|
||||||
|
while src[result] in {'\t', ' '}: inc(result)
|
||||||
|
while src[result] notin {'\t', ' ', '\0'}:
|
||||||
|
add(a, src[result])
|
||||||
|
inc(result)
|
||||||
|
|
||||||
|
proc scanNumber(src: string, a: var int, start: int): int =
|
||||||
|
result = start
|
||||||
|
a = 0
|
||||||
|
while src[result] in {'\t', ' '}: inc(result)
|
||||||
|
while true:
|
||||||
|
case src[result]
|
||||||
|
of '0'..'9': a = a * 10 + ord(src[result]) - ord('0')
|
||||||
|
of '_': nil # skip underscores (nice for long line numbers)
|
||||||
|
else: break
|
||||||
|
inc(result)
|
||||||
|
|
||||||
|
proc dbgHelp() =
|
||||||
|
debugOut("""
|
||||||
|
list of commands (see the manual for further help):
|
||||||
|
GENERAL
|
||||||
|
h, help display this help message
|
||||||
|
q, quit quit the debugger and the program
|
||||||
|
<ENTER> repeat the previous debugger command
|
||||||
|
EXECUTING
|
||||||
|
s, stepinto single step, stepping into routine calls
|
||||||
|
n, stepover single step, without stepping into routine calls
|
||||||
|
f, skipcurrent continue execution until the current routine finishes
|
||||||
|
c, continue continue execution until the next breakpoint
|
||||||
|
i, ignore continue execution, ignore all breakpoints
|
||||||
|
BREAKPOINTS
|
||||||
|
b, setbreak <name> [fromline [toline]] [file]
|
||||||
|
set a new breakpoint named 'name' for line and file
|
||||||
|
if line or file are omitted the current one is used
|
||||||
|
breakpoints display the entire breakpoint list
|
||||||
|
disable <name> disable a breakpoint
|
||||||
|
enable <name> enable a breakpoint
|
||||||
|
DATA DISPLAY
|
||||||
|
e, eval <exp> evaluate the expression <exp>
|
||||||
|
o, out <file> <exp> evaluate <exp> and write it to <file>
|
||||||
|
w, where display the current execution point
|
||||||
|
stackframe [file] display current stack frame [and write it to file]
|
||||||
|
u, up go up in the call stack
|
||||||
|
d, down go down in the call stack
|
||||||
|
callstack display the entire call stack
|
||||||
|
l, locals display available local variables
|
||||||
|
g, globals display available global variables
|
||||||
|
maxdisplay <integer> set the display's recursion maximum
|
||||||
|
""")
|
||||||
|
|
||||||
|
proc InvalidCommand() =
|
||||||
|
debugOut("[Warning] invalid command ignored (type 'h' for help) ")
|
||||||
|
|
||||||
|
proc hasExt(s: string): bool =
|
||||||
|
# returns true if s has a filename extension
|
||||||
|
for i in countdown(len(s)-1, 0):
|
||||||
|
if s[i] == '.': return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc setBreakPoint(s: string, start: int) =
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanWord(s, dbgTemp, start)
|
||||||
|
if i <= start:
|
||||||
|
InvalidCommand()
|
||||||
|
return
|
||||||
|
if dbgBPlen >= high(dbgBP):
|
||||||
|
debugOut("[Warning] no breakpoint could be set; out of breakpoint space ")
|
||||||
|
return
|
||||||
|
var x = dbgBPlen
|
||||||
|
inc(dbgBPlen)
|
||||||
|
dbgBP[x].name = dbgTemp
|
||||||
|
i = scanNumber(s, dbgBP[x].low, i)
|
||||||
|
if dbgBP[x].low == 0:
|
||||||
|
# set to current line:
|
||||||
|
dbgBP[x].low = framePtr.line
|
||||||
|
i = scanNumber(s, dbgBP[x].high, i)
|
||||||
|
if dbgBP[x].high == 0: # set to low:
|
||||||
|
dbgBP[x].high = dbgBP[x].low
|
||||||
|
i = scanFilename(s, dbgTemp, i)
|
||||||
|
if not (dbgTemp.len == 0):
|
||||||
|
if not hasExt(dbgTemp): add(dbgTemp, ".nim")
|
||||||
|
dbgBP[x].filename = dbgTemp
|
||||||
|
else: # use current filename
|
||||||
|
dbgBP[x].filename = $framePtr.filename
|
||||||
|
# skip whitespace:
|
||||||
|
while s[i] in {' ', '\t'}: inc(i)
|
||||||
|
if s[i] != '\0':
|
||||||
|
dec(dbgBPLen) # remove buggy breakpoint
|
||||||
|
InvalidCommand()
|
||||||
|
|
||||||
|
proc BreakpointSetEnabled(s: string, start, enabled: int) =
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanWord(s, dbgTemp, start)
|
||||||
|
if i <= start:
|
||||||
|
InvalidCommand()
|
||||||
|
return
|
||||||
|
var x = findBreakpoint(dbgTemp)
|
||||||
|
if x < 0: debugOut("[Warning] breakpoint does not exist ")
|
||||||
|
elif enabled * dbgBP[x].low < 0: # signs are different?
|
||||||
|
dbgBP[x].low = -dbgBP[x].low
|
||||||
|
dbgBP[x].high = -dbgBP[x].high
|
||||||
|
|
||||||
|
proc dbgEvaluate(stream: TFile, s: string, start: int,
|
||||||
|
currFrame: PExtendedFrame) =
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanWord(s, dbgTemp, start)
|
||||||
|
while s[i] in {' ', '\t'}: inc(i)
|
||||||
|
var f = currFrame
|
||||||
|
if s[i] == '.':
|
||||||
|
inc(i) # skip '.'
|
||||||
|
add(dbgTemp, '.')
|
||||||
|
i = scanAndAppendWord(s, dbgTemp, i)
|
||||||
|
# search for global var:
|
||||||
|
f = addr(dbgGlobalData)
|
||||||
|
if s[i] != '\0':
|
||||||
|
debugOut("[Warning] could not parse expr ")
|
||||||
|
return
|
||||||
|
var j = findVariable(f, dbgTemp)
|
||||||
|
if j < 0:
|
||||||
|
debugOut("[Warning] could not find variable ")
|
||||||
|
return
|
||||||
|
writeVariable(stream, f.slots[j])
|
||||||
|
|
||||||
|
proc dbgOut(s: string, start: int, currFrame: PExtendedFrame) =
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanFilename(s, dbgTemp, start)
|
||||||
|
if dbgTemp.len == 0:
|
||||||
|
InvalidCommand()
|
||||||
|
return
|
||||||
|
var stream = openAppend(dbgTemp)
|
||||||
|
if stream == nil:
|
||||||
|
debugOut("[Warning] could not open or create file ")
|
||||||
|
return
|
||||||
|
dbgEvaluate(stream, s, i, currFrame)
|
||||||
|
closeFile(stream)
|
||||||
|
|
||||||
|
proc dbgStackFrame(s: string, start: int, currFrame: PExtendedFrame) =
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanFilename(s, dbgTemp, start)
|
||||||
|
if dbgTemp.len == 0:
|
||||||
|
# just write it to stdout:
|
||||||
|
ListFrame(stdout, currFrame)
|
||||||
|
else:
|
||||||
|
var stream = openAppend(dbgTemp)
|
||||||
|
if stream == nil:
|
||||||
|
debugOut("[Warning] could not open or create file ")
|
||||||
|
return
|
||||||
|
ListFrame(stream, currFrame)
|
||||||
|
closeFile(stream)
|
||||||
|
|
||||||
|
proc CommandPrompt() =
|
||||||
|
# if we return from this routine, user code executes again
|
||||||
|
var
|
||||||
|
again: bool = True
|
||||||
|
dbgFramePtr = framePtr # for going down and up the stack
|
||||||
|
dbgDown: int = 0 # how often we did go down
|
||||||
|
|
||||||
|
while again:
|
||||||
|
write(stdout, "*** emdb| >>")
|
||||||
|
var tmp = readLine(stdin)
|
||||||
|
if tmp.len > 0: dbgUser = tmp
|
||||||
|
# now look what we have to do:
|
||||||
|
var dbgTemp: string
|
||||||
|
var i = scanWord(dbgUser, dbgTemp, 0)
|
||||||
|
case dbgTemp
|
||||||
|
of "": InvalidCommand()
|
||||||
|
of "s", "stepinto":
|
||||||
|
dbgState = dbStepInto
|
||||||
|
again = false
|
||||||
|
of "n", "stepover":
|
||||||
|
dbgState = dbStepOver
|
||||||
|
dbgSkipToFrame = framePtr
|
||||||
|
again = false
|
||||||
|
of "f", "skipcurrent":
|
||||||
|
dbgState = dbSkipCurrent
|
||||||
|
dbgSkipToFrame = framePtr.prev
|
||||||
|
again = false
|
||||||
|
of "c", "continue":
|
||||||
|
dbgState = dbBreakpoints
|
||||||
|
again = false
|
||||||
|
of "i", "ignore":
|
||||||
|
dbgState = dbOff
|
||||||
|
again = false
|
||||||
|
of "h", "help":
|
||||||
|
dbgHelp()
|
||||||
|
of "q", "quit":
|
||||||
|
dbgState = dbQuiting
|
||||||
|
dbgAborting = True
|
||||||
|
again = false
|
||||||
|
quit(1) # BUGFIX: quit with error code > 0
|
||||||
|
of "e", "eval":
|
||||||
|
dbgEvaluate(stdout, dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
|
||||||
|
of "o", "out":
|
||||||
|
dbgOut(dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
|
||||||
|
of "stackframe":
|
||||||
|
dbgStackFrame(dbgUser, i, cast[PExtendedFrame](dbgFramePtr))
|
||||||
|
of "w", "where":
|
||||||
|
dbgShowExecutionPoint()
|
||||||
|
of "l", "locals":
|
||||||
|
ListVariables(stdout, cast[PExtendedFrame](dbgFramePtr))
|
||||||
|
of "g", "globals":
|
||||||
|
ListVariables(stdout, addr(dbgGlobalData))
|
||||||
|
of "u", "up":
|
||||||
|
if dbgDown <= 0:
|
||||||
|
debugOut("[Warning] cannot go up any further ")
|
||||||
|
else:
|
||||||
|
dbgFramePtr = framePtr
|
||||||
|
for j in 0 .. dbgDown-2: # BUGFIX
|
||||||
|
dbgFramePtr = dbgFramePtr.prev
|
||||||
|
dec(dbgDown)
|
||||||
|
dbgShowCurrentProc(dbgFramePtr)
|
||||||
|
of "d", "down":
|
||||||
|
if dbgFramePtr != nil:
|
||||||
|
inc(dbgDown)
|
||||||
|
dbgFramePtr = dbgFramePtr.prev
|
||||||
|
dbgShowCurrentProc(dbgFramePtr)
|
||||||
|
else:
|
||||||
|
debugOut("[Warning] cannot go down any further ")
|
||||||
|
of "callstack":
|
||||||
|
WriteStackTrace()
|
||||||
|
of "b", "setbreak":
|
||||||
|
setBreakPoint(dbgUser, i)
|
||||||
|
of "breakpoints":
|
||||||
|
ListBreakPoints()
|
||||||
|
of "disable":
|
||||||
|
BreakpointSetEnabled(dbgUser, i, -1)
|
||||||
|
of "enable":
|
||||||
|
BreakpointSetEnabled(dbgUser, i, +1)
|
||||||
|
of "maxdisplay":
|
||||||
|
var parsed: int
|
||||||
|
i = scanNumber(dbgUser, parsed, i)
|
||||||
|
if dbgUser[i-1] in {'0'..'9'}:
|
||||||
|
if parsed == 0: maxDisplayRecDepth = -1
|
||||||
|
else: maxDisplayRecDepth = parsed
|
||||||
|
else:
|
||||||
|
InvalidCommand()
|
||||||
|
else:
|
||||||
|
InvalidCommand()
|
||||||
|
|
||||||
|
proc endbStep() =
|
||||||
|
# we get into here if an unhandled exception has been raised
|
||||||
|
# XXX: do not allow the user to run the program any further?
|
||||||
|
# XXX: BUG: the frame is lost here!
|
||||||
|
dbgShowExecutionPoint()
|
||||||
|
CommandPrompt()
|
||||||
|
|
||||||
|
proc checkForBreakpoint() =
|
||||||
|
var i = dbgBreakpointReached(framePtr.line)
|
||||||
|
if i >= 0:
|
||||||
|
write(stdout, "*** emdb| reached ")
|
||||||
|
write(stdout, dbgBP[i].name)
|
||||||
|
write(stdout, " in ")
|
||||||
|
write(stdout, framePtr.filename)
|
||||||
|
write(stdout, "(")
|
||||||
|
write(stdout, framePtr.line)
|
||||||
|
write(stdout, ") ")
|
||||||
|
write(stdout, framePtr.procname)
|
||||||
|
write(stdout, " ***\n")
|
||||||
|
CommandPrompt()
|
||||||
|
|
||||||
|
# interface to the user program:
|
||||||
|
|
||||||
|
proc dbgRegisterBreakpoint(line: int,
|
||||||
|
filename, name: cstring) {.compilerproc.} =
|
||||||
|
var x = dbgBPlen
|
||||||
|
inc(dbgBPlen)
|
||||||
|
dbgBP[x].name = $name
|
||||||
|
dbgBP[x].filename = $filename
|
||||||
|
dbgBP[x].low = line
|
||||||
|
dbgBP[x].high = line
|
||||||
|
|
||||||
|
proc dbgRegisterGlobal(name: cstring, address: pointer,
|
||||||
|
typ: PNimType) {.compilerproc.} =
|
||||||
|
var i = dbgGlobalData.f.len
|
||||||
|
if i >= high(dbgGlobalData.slots):
|
||||||
|
debugOut("[Warning] cannot register global ")
|
||||||
|
return
|
||||||
|
dbgGlobalData.slots[i].name = name
|
||||||
|
dbgGlobalData.slots[i].typ = typ
|
||||||
|
dbgGlobalData.slots[i].address = address
|
||||||
|
inc(dbgGlobalData.f.len)
|
||||||
|
|
||||||
|
proc endb(line: int) {.compilerproc.} =
|
||||||
|
# This proc is called before any Nimrod code line!
|
||||||
|
# Thus, it must have as few parameters as possible to keep the
|
||||||
|
# code size small!
|
||||||
|
# check if we are at an enabled breakpoint or "in the mood"
|
||||||
|
framePtr.line = line # this is done here for smaller code size!
|
||||||
|
if dbgLineHook != nil: dbgLineHook()
|
||||||
|
case dbgState
|
||||||
|
of dbStepInto:
|
||||||
|
# we really want the command prompt here:
|
||||||
|
dbgShowExecutionPoint()
|
||||||
|
CommandPrompt()
|
||||||
|
of dbSkipCurrent, dbStepOver: # skip current routine
|
||||||
|
if framePtr == dbgSkipToFrame:
|
||||||
|
dbgShowExecutionPoint()
|
||||||
|
CommandPrompt()
|
||||||
|
else: # breakpoints are wanted though (I guess)
|
||||||
|
checkForBreakpoint()
|
||||||
|
of dbBreakpoints: # debugger is only interested in breakpoints
|
||||||
|
checkForBreakpoint()
|
||||||
|
else: nil
|
||||||
5071
lib/dlmalloc.c
Executable file
5071
lib/dlmalloc.c
Executable file
File diff suppressed because it is too large
Load diff
1143
lib/dlmalloc.h
Executable file
1143
lib/dlmalloc.h
Executable file
File diff suppressed because it is too large
Load diff
143
lib/dyncalls.nim
Executable file
143
lib/dyncalls.nim
Executable file
|
|
@ -0,0 +1,143 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file implements the ability to call native procs from libraries.
|
||||||
|
# It is not possible to do this in a platform independant way, unfortunately.
|
||||||
|
# However, the interface has been designed to take platform differences into
|
||||||
|
# account and been ported to all major platforms.
|
||||||
|
#
|
||||||
|
# interface
|
||||||
|
|
||||||
|
type
|
||||||
|
EInvalidLibrary = object of EOS
|
||||||
|
|
||||||
|
when defined(windows) or defined(dos):
|
||||||
|
{.define: USE_DLL.}
|
||||||
|
elif defined(posix):
|
||||||
|
{.define: USE_DLOPEN.}
|
||||||
|
elif defined(mac):
|
||||||
|
{.define: USE_DYLD.}
|
||||||
|
|
||||||
|
type
|
||||||
|
TLibHandle = pointer # private type
|
||||||
|
TProcAddr = pointer # libary loading and loading of procs:
|
||||||
|
|
||||||
|
const
|
||||||
|
NilLibHandle: TLibHandle = nil
|
||||||
|
|
||||||
|
proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
|
||||||
|
proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
|
||||||
|
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
|
||||||
|
|
||||||
|
#implementation
|
||||||
|
|
||||||
|
# this code was inspired from Lua's source code:
|
||||||
|
# Lua - An Extensible Extension Language
|
||||||
|
# Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
|
||||||
|
# http://www.lua.org
|
||||||
|
# mailto:info@lua.org
|
||||||
|
|
||||||
|
when defined(USE_DLOPEN):
|
||||||
|
#
|
||||||
|
# =========================================================================
|
||||||
|
# This is an implementation based on the dlfcn interface.
|
||||||
|
# The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
||||||
|
# NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
||||||
|
# as an emulation layer on top of native functions.
|
||||||
|
# =========================================================================
|
||||||
|
#
|
||||||
|
|
||||||
|
# c stuff:
|
||||||
|
var
|
||||||
|
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
|
||||||
|
|
||||||
|
proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
|
||||||
|
proc dlopen(path: CString, mode: int): TLibHandle {.
|
||||||
|
importc, header: "<dlfcn.h>".}
|
||||||
|
proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
|
||||||
|
importc, header: "<dlfcn.h>".}
|
||||||
|
|
||||||
|
proc nimUnloadLibrary(lib: TLibHandle) =
|
||||||
|
dlclose(lib)
|
||||||
|
|
||||||
|
proc nimLoadLibrary(path: string): TLibHandle =
|
||||||
|
result = dlopen(path, RTLD_NOW)
|
||||||
|
if result == nil:
|
||||||
|
raise newException(EInvalidLibrary, "could not load: " & path)
|
||||||
|
|
||||||
|
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
|
||||||
|
result = dlsym(lib, name)
|
||||||
|
|
||||||
|
elif defined(USE_DLL):
|
||||||
|
#
|
||||||
|
# =======================================================================
|
||||||
|
# Native Windows Implementation
|
||||||
|
# =======================================================================
|
||||||
|
#
|
||||||
|
type
|
||||||
|
THINSTANCE {.importc: "HINSTANCE".} = pointer
|
||||||
|
|
||||||
|
proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
|
||||||
|
proc winLoadLibrary(path: cstring): THINSTANCE {.
|
||||||
|
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
|
||||||
|
proc GetProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
|
||||||
|
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
|
||||||
|
|
||||||
|
proc nimUnloadLibrary(lib: TLibHandle) =
|
||||||
|
FreeLibrary(cast[THINSTANCE](lib))
|
||||||
|
|
||||||
|
proc nimLoadLibrary(path: string): TLibHandle =
|
||||||
|
result = cast[TLibHandle](winLoadLibrary(path))
|
||||||
|
if result == nil:
|
||||||
|
raise newException(EInvalidLibrary, "could not load: " & path)
|
||||||
|
|
||||||
|
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
|
||||||
|
result = GetProcAddress(cast[THINSTANCE](lib), name)
|
||||||
|
|
||||||
|
elif defined(USE_DYLD):
|
||||||
|
#
|
||||||
|
# =======================================================================
|
||||||
|
# Native Mac OS X / Darwin Implementation
|
||||||
|
# =======================================================================
|
||||||
|
#
|
||||||
|
{.error: "no implementation for dyncalls yet".}
|
||||||
|
|
||||||
|
proc nimUnloadLibrary(lib: TLibHandle) =
|
||||||
|
NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
|
||||||
|
|
||||||
|
var
|
||||||
|
dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
|
||||||
|
|
||||||
|
proc nimLoadLibrary(path: string): TLibHandle =
|
||||||
|
var
|
||||||
|
img: NSObjectFileImage
|
||||||
|
ret: NSObjectFileImageReturnCode
|
||||||
|
modul: NSModule
|
||||||
|
# this would be a rare case, but prevents crashing if it happens
|
||||||
|
result = nil
|
||||||
|
if dyld_present != 0:
|
||||||
|
ret = NSCreateObjectFileImageFromFile(path, addr(img))
|
||||||
|
if ret == NSObjectFileImageSuccess:
|
||||||
|
modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
|
||||||
|
NSLINKMODULE_OPTION_RETURN_ON_ERROR)
|
||||||
|
NSDestroyObjectFileImage(img)
|
||||||
|
result = TLibHandle(modul)
|
||||||
|
if result == nil:
|
||||||
|
raise newException(EInvalidLibrary, "could not load: " & path)
|
||||||
|
|
||||||
|
proc nimGetProcAddr(lib: TLibHandle, cname: string): TProcAddr =
|
||||||
|
var
|
||||||
|
nss: NSSymbol
|
||||||
|
nss = NSLookupSymbolInModule(NSModule(lib), name)
|
||||||
|
result = TProcAddr(NSAddressOfSymbol(nss))
|
||||||
|
|
||||||
|
else: # workaround a newly introduced bug :-(
|
||||||
|
{.error: "no implementation for dyncalls".}
|
||||||
251
lib/excpt.nim
Executable file
251
lib/excpt.nim
Executable file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Exception handling code. This is difficult because it has
|
||||||
|
# to work if there is no more memory. Thus we have to use
|
||||||
|
# a static string. Do not use ``sprintf``, etc. as they are
|
||||||
|
# unsafe!
|
||||||
|
|
||||||
|
when not defined(windows) or not defined(guiapp):
|
||||||
|
proc writeToStdErr(msg: CString) = write(stdout, msg)
|
||||||
|
|
||||||
|
else:
|
||||||
|
proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
|
||||||
|
header: "<windows.h>", nodecl.}
|
||||||
|
|
||||||
|
proc writeToStdErr(msg: CString) =
|
||||||
|
discard MessageBoxA(0, msg, nil, 0)
|
||||||
|
|
||||||
|
proc raiseException(e: ref E_Base, ename: CString) {.compilerproc.}
|
||||||
|
proc reraiseException() {.compilerproc.}
|
||||||
|
|
||||||
|
proc registerSignalHandler() {.compilerproc.}
|
||||||
|
|
||||||
|
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
|
||||||
|
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
|
||||||
|
proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
|
||||||
|
proc chckNil(p: pointer) {.inline, compilerproc.}
|
||||||
|
|
||||||
|
type
|
||||||
|
PSafePoint = ptr TSafePoint
|
||||||
|
TSafePoint {.compilerproc.} = record
|
||||||
|
prev: PSafePoint # points to next safe point ON THE STACK
|
||||||
|
exc: ref E_Base
|
||||||
|
status: int
|
||||||
|
context: C_JmpBuf
|
||||||
|
|
||||||
|
var
|
||||||
|
excHandler {.compilerproc, volatile.}: PSafePoint = nil
|
||||||
|
# list of exception handlers
|
||||||
|
# a global variable for the root of all try blocks
|
||||||
|
|
||||||
|
proc reraiseException() =
|
||||||
|
if excHandler != nil:
|
||||||
|
raise newException(ENoExceptionToReraise, "no exception to reraise")
|
||||||
|
else:
|
||||||
|
c_longjmp(excHandler.context, 1)
|
||||||
|
|
||||||
|
type
|
||||||
|
PFrame = ptr TFrame
|
||||||
|
TFrame {.importc, nodecl.} = record
|
||||||
|
prev: PFrame
|
||||||
|
procname: CString
|
||||||
|
line: int # current line number
|
||||||
|
filename: CString
|
||||||
|
len: int # length of slots (when not debugging always zero)
|
||||||
|
|
||||||
|
TTempFrame = record # used for recursion elimination in WriteStackTrace
|
||||||
|
procname: CString
|
||||||
|
line: int
|
||||||
|
|
||||||
|
var
|
||||||
|
buf: string # cannot be allocated on the stack!
|
||||||
|
assertBuf: string # we need a different buffer for
|
||||||
|
# assert, as it raises an exception and
|
||||||
|
# exception handler needs the buffer too
|
||||||
|
|
||||||
|
framePtr {.exportc, volatile.}: PFrame
|
||||||
|
|
||||||
|
tempFrames: array [0..255, TTempFrame] # cannot be allocated
|
||||||
|
# on the stack!
|
||||||
|
|
||||||
|
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||||
|
var
|
||||||
|
it = f
|
||||||
|
i = 0
|
||||||
|
total = 0
|
||||||
|
while it != nil and i <= high(tempFrames):
|
||||||
|
tempFrames[i].procname = it.procname
|
||||||
|
tempFrames[i].line = it.line
|
||||||
|
inc(i)
|
||||||
|
inc(total)
|
||||||
|
it = it.prev
|
||||||
|
while it != nil:
|
||||||
|
inc(total)
|
||||||
|
it = it.prev
|
||||||
|
# if the buffer overflowed print '...':
|
||||||
|
if total != i:
|
||||||
|
add(s, "(")
|
||||||
|
add(s, $(total-i))
|
||||||
|
add(s, " calls omitted) ...\n")
|
||||||
|
for j in countdown(i-1, 0):
|
||||||
|
add(s, $tempFrames[j].procname)
|
||||||
|
if tempFrames[j].line > 0:
|
||||||
|
add(s, ", line: ")
|
||||||
|
add(s, $tempFrames[j].line)
|
||||||
|
add(s, "\n")
|
||||||
|
|
||||||
|
proc rawWriteStackTrace(s: var string) =
|
||||||
|
if framePtr == nil:
|
||||||
|
add(s, "No stack traceback available\n")
|
||||||
|
else:
|
||||||
|
add(s, "Traceback (most recent call last)\n")
|
||||||
|
auxWriteStackTrace(framePtr, s)
|
||||||
|
|
||||||
|
proc quitOrDebug() {.inline.} =
|
||||||
|
when not defined(emdb):
|
||||||
|
quit(1)
|
||||||
|
else:
|
||||||
|
emdbStep() # call the debugger
|
||||||
|
|
||||||
|
proc raiseException(e: ref E_Base, ename: CString) =
|
||||||
|
GC_disable() # a bad thing is an error in the GC while raising an exception
|
||||||
|
e.name = ename
|
||||||
|
if excHandler != nil:
|
||||||
|
excHandler.exc = e
|
||||||
|
c_longjmp(excHandler.context, 1)
|
||||||
|
else:
|
||||||
|
if cast[pointer](buf) != nil:
|
||||||
|
setLen(buf, 0)
|
||||||
|
rawWriteStackTrace(buf)
|
||||||
|
if e.msg != nil and e.msg[0] != '\0':
|
||||||
|
add(buf, "Error: unhandled exception: ")
|
||||||
|
add(buf, $e.msg)
|
||||||
|
else:
|
||||||
|
add(buf, "Error: unhandled exception")
|
||||||
|
add(buf, " [")
|
||||||
|
add(buf, $ename)
|
||||||
|
add(buf, "]\n")
|
||||||
|
writeToStdErr(buf)
|
||||||
|
else:
|
||||||
|
writeToStdErr("*** FATAL ERROR *** ")
|
||||||
|
writeToStdErr(ename)
|
||||||
|
writeToStdErr("\n")
|
||||||
|
quitOrDebug()
|
||||||
|
GC_enable()
|
||||||
|
|
||||||
|
var
|
||||||
|
gAssertionFailed: ref EAssertionFailed
|
||||||
|
|
||||||
|
proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
|
||||||
|
if not cond:
|
||||||
|
GC_disable() # BUGFIX: `$` allocates a new string object!
|
||||||
|
if cast[pointer](assertBuf) != nil: # BUGFIX: when debugging the GC, assertBuf may be nil
|
||||||
|
setLen(assertBuf, 0)
|
||||||
|
add(assertBuf, "[Assertion failure] file: ")
|
||||||
|
add(assertBuf, file)
|
||||||
|
add(assertBuf, " line: ")
|
||||||
|
add(assertBuf, $line)
|
||||||
|
add(assertBuf, "\n")
|
||||||
|
gAssertionFailed.msg = assertBuf
|
||||||
|
GC_enable()
|
||||||
|
raise gAssertionFailed # newException(EAssertionFailed, assertBuf)
|
||||||
|
|
||||||
|
proc WriteStackTrace() =
|
||||||
|
var
|
||||||
|
s: string = ""
|
||||||
|
rawWriteStackTrace(s)
|
||||||
|
writeToStdErr(s)
|
||||||
|
|
||||||
|
var
|
||||||
|
dbgAborting: bool # whether the debugger wants to abort
|
||||||
|
|
||||||
|
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
|
||||||
|
# print stack trace and quit
|
||||||
|
var
|
||||||
|
s = int(sig)
|
||||||
|
setLen(buf, 0)
|
||||||
|
rawWriteStackTrace(buf)
|
||||||
|
|
||||||
|
if s == SIGINT: add(buf, "SIGINT: Interrupted by Ctrl-C.\n")
|
||||||
|
elif s == SIGSEGV: add(buf, "SIGSEGV: Illegal storage access.\n")
|
||||||
|
elif s == SIGABRT:
|
||||||
|
if dbgAborting: return # the debugger wants to abort
|
||||||
|
add(buf, "SIGABRT: Abnormal termination.\n")
|
||||||
|
elif s == SIGFPE: add(buf, "SIGFPE: Arithmetic error.\n")
|
||||||
|
elif s == SIGILL: add(buf, "SIGILL: Illegal operation.\n")
|
||||||
|
elif s == SIGBUS: add(buf, "SIGBUS: Illegal storage access.\n")
|
||||||
|
else: add(buf, "unknown signal\n")
|
||||||
|
writeToStdErr(buf)
|
||||||
|
dbgAborting = True # play safe here...
|
||||||
|
quit(1) # always quit when SIGABRT
|
||||||
|
|
||||||
|
proc registerSignalHandler() =
|
||||||
|
c_signal(SIGINT, signalHandler)
|
||||||
|
c_signal(SIGSEGV, signalHandler)
|
||||||
|
c_signal(SIGABRT, signalHandler)
|
||||||
|
c_signal(SIGFPE, signalHandler)
|
||||||
|
c_signal(SIGILL, signalHandler)
|
||||||
|
c_signal(SIGBUS, signalHandler)
|
||||||
|
|
||||||
|
registerSignalHandler() # call it in initialization section
|
||||||
|
# for easier debugging of the GC, this memory is only allocated after the
|
||||||
|
# signal handlers have been registered
|
||||||
|
new(gAssertionFailed)
|
||||||
|
buf = newString(2048)
|
||||||
|
assertBuf = newString(2048)
|
||||||
|
setLen(buf, 0)
|
||||||
|
setLen(assertBuf, 0)
|
||||||
|
|
||||||
|
proc raiseRangeError() {.compilerproc, noreturn.} =
|
||||||
|
raise newException(EOutOfRange, "value out of range")
|
||||||
|
|
||||||
|
proc raiseIndexError() {.compilerproc, noreturn.} =
|
||||||
|
raise newException(EInvalidIndex, "index out of bounds")
|
||||||
|
|
||||||
|
proc chckIndx(i, a, b: int): int =
|
||||||
|
if i >= a and i <= b:
|
||||||
|
return i
|
||||||
|
else:
|
||||||
|
raiseIndexError()
|
||||||
|
|
||||||
|
proc chckRange(i, a, b: int): int =
|
||||||
|
if i >= a and i <= b:
|
||||||
|
return i
|
||||||
|
else:
|
||||||
|
raiseRangeError()
|
||||||
|
|
||||||
|
proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
|
||||||
|
if i >= a and i <= b:
|
||||||
|
return i
|
||||||
|
else:
|
||||||
|
raiseRangeError()
|
||||||
|
|
||||||
|
proc chckRangeF(x, a, b: float): float =
|
||||||
|
if x >= a and x <= b:
|
||||||
|
return x
|
||||||
|
else:
|
||||||
|
raiseRangeError()
|
||||||
|
|
||||||
|
proc chckNil(p: pointer) =
|
||||||
|
if p == nil: c_raise(SIGSEGV)
|
||||||
|
|
||||||
|
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
|
||||||
|
# checks if obj is of type subclass:
|
||||||
|
var x = obj
|
||||||
|
if x == subclass: return # optimized fast path
|
||||||
|
while x != subclass:
|
||||||
|
if x == nil:
|
||||||
|
raise newException(EInvalidObjectConversion, "invalid object conversion")
|
||||||
|
x = x.base
|
||||||
|
|
||||||
|
proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
|
||||||
|
if a != b:
|
||||||
|
raise newException(EInvalidObjectAssignment, "invalid object assignment")
|
||||||
897
lib/gc.nim
Executable file
897
lib/gc.nim
Executable file
|
|
@ -0,0 +1,897 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Garbage Collector
|
||||||
|
|
||||||
|
# For a description of the algorithms used here see:
|
||||||
|
# intern.html
|
||||||
|
|
||||||
|
#{.define: debugGC.} # we wish to debug the GC...
|
||||||
|
|
||||||
|
#when defined(debugGC):
|
||||||
|
# {.define: logGC.} # define if the GC should log some of its activities
|
||||||
|
|
||||||
|
{.define: cycleGC.}
|
||||||
|
|
||||||
|
# Guess the page size of the system; if it is the
|
||||||
|
# wrong value, performance may be worse (this is not
|
||||||
|
# for sure though), but GC still works; must be a power of two!
|
||||||
|
const
|
||||||
|
PageSize = 1024 * sizeof(int)
|
||||||
|
RC_Increase = 7 * PageSize # is an additive increase
|
||||||
|
CycleIncrease = 2 # is a multiplicative increase
|
||||||
|
|
||||||
|
when defined(debugGC):
|
||||||
|
const InitialThreshold = 64*1024
|
||||||
|
const stressGC = True # GC is debugged; no need to stress it
|
||||||
|
else:
|
||||||
|
const stressGC = False
|
||||||
|
const InitialThreshold = RC_Increase
|
||||||
|
# this may need benchmarking...
|
||||||
|
|
||||||
|
# things the System module thinks should be available:
|
||||||
|
when defined(useDL) or defined(nativeDL):
|
||||||
|
type
|
||||||
|
TMallocInfo {.importc: "struct mallinfo", nodecl.} = record
|
||||||
|
arena: cint # non-mmapped space allocated from system
|
||||||
|
ordblks: cint # number of free chunks
|
||||||
|
smblks: cint # number of fastbin blocks
|
||||||
|
hblks: cint # number of mmapped regions
|
||||||
|
hblkhd: cint # space in mmapped regions
|
||||||
|
usmblks: cint # maximum total allocated space
|
||||||
|
fsmblks: cint # space available in freed fastbin blocks
|
||||||
|
uordblks: cint # total allocated space
|
||||||
|
fordblks: cint # total free space
|
||||||
|
keepcost: cint # top-most, releasable (via malloc_trim) space
|
||||||
|
|
||||||
|
when defined(useDL):
|
||||||
|
proc mallinfo: TMallocInfo {.importc: "dlmallinfo", nodecl.}
|
||||||
|
elif defined(nativeDL):
|
||||||
|
proc mallinfo: TMallocInfo {.importc: "mallinfo", nodecl.}
|
||||||
|
|
||||||
|
when defined(useDL) or defined(nativeDL):
|
||||||
|
proc getOccupiedMem(): int = return mallinfo().uordblks
|
||||||
|
proc getFreeMem(): int = return mallinfo().fordblks
|
||||||
|
proc getTotalMem(): int =
|
||||||
|
var m = mallinfo()
|
||||||
|
return int(m.hblkhd) + int(m.arena)
|
||||||
|
else: # not available:
|
||||||
|
proc getOccupiedMem(): int = return -1
|
||||||
|
proc getFreeMem(): int = return -1
|
||||||
|
proc getTotalMem(): int = return -1
|
||||||
|
|
||||||
|
var
|
||||||
|
rcThreshold: int = InitialThreshold
|
||||||
|
cycleThreshold: int = InitialThreshold
|
||||||
|
|
||||||
|
memUsed: int = 0 # we have to keep track how much we have allocated
|
||||||
|
|
||||||
|
recGcLock: int = 0
|
||||||
|
# we use a lock to prevend the garbage collector to
|
||||||
|
# be triggered in a finalizer; the collector should not call
|
||||||
|
# itself this way! Thus every object allocated by a finalizer
|
||||||
|
# will not trigger a garbage collection. This is wasteful but safe.
|
||||||
|
# This is a lock against recursive garbage collection, not a lock for
|
||||||
|
# threads!
|
||||||
|
|
||||||
|
when defined(useDL) and not defined(nativeDL):
|
||||||
|
{.compile: "dlmalloc.c".}
|
||||||
|
|
||||||
|
type
|
||||||
|
TFinalizer {.compilerproc.} = proc (self: pointer)
|
||||||
|
# A ref type can have a finalizer that is called before the object's
|
||||||
|
# storage is freed.
|
||||||
|
PPointer = ptr pointer
|
||||||
|
|
||||||
|
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc.}
|
||||||
|
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.}
|
||||||
|
# unsureAsgnRef updates the reference counters only if dest is not on the
|
||||||
|
# stack. It is used by the code generator if it cannot decide wether a
|
||||||
|
# reference is in the stack or not (this can happen for out/var parameters).
|
||||||
|
proc growObj(old: pointer, newsize: int): pointer {.compilerproc.}
|
||||||
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.}
|
||||||
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.}
|
||||||
|
|
||||||
|
# implementation:
|
||||||
|
|
||||||
|
when defined(useDL):
|
||||||
|
proc nimSize(p: pointer): int {.
|
||||||
|
importc: "dlmalloc_usable_size", header: "dlmalloc.h".}
|
||||||
|
elif defined(nativeDL):
|
||||||
|
proc nimSize(p: pointer): int {.
|
||||||
|
importc: "malloc_usable_size", header: "<malloc.h>".}
|
||||||
|
|
||||||
|
type
|
||||||
|
TWalkOp = enum
|
||||||
|
waNone, waRelease, waZctDecRef, waCycleDecRef, waCycleIncRef, waDebugIncRef
|
||||||
|
|
||||||
|
TCollectorData = int
|
||||||
|
TCell = record
|
||||||
|
refcount: TCollectorData # the refcount and bit flags
|
||||||
|
typ: PNimType
|
||||||
|
stackcount: int # stack counter for debugging
|
||||||
|
drefc: int # real reference counter for debugging
|
||||||
|
|
||||||
|
PCell = ptr TCell
|
||||||
|
|
||||||
|
var
|
||||||
|
gOutOfMem: ref EOutOfMemory
|
||||||
|
|
||||||
|
proc raiseOutOfMem() {.noreturn.} =
|
||||||
|
if gOutOfMem == nil:
|
||||||
|
writeToStdErr("out of memory; cannot even throw an exception")
|
||||||
|
quit(1)
|
||||||
|
gOutOfMem.msg = "out of memory"
|
||||||
|
raise gOutOfMem
|
||||||
|
|
||||||
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
|
result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
|
||||||
|
|
||||||
|
proc usrToCell(usr: pointer): PCell {.inline.} =
|
||||||
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
|
result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
|
||||||
|
|
||||||
|
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
||||||
|
# used for code generation concerning debugging
|
||||||
|
result = usrToCell(c).typ
|
||||||
|
|
||||||
|
proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
|
||||||
|
result = int(usrToCell(p).refcount)
|
||||||
|
|
||||||
|
proc gcAlloc(size: int): pointer =
|
||||||
|
result = alloc0(size)
|
||||||
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
||||||
|
proc GC_disable() = inc(recGcLock)
|
||||||
|
proc GC_enable() =
|
||||||
|
if recGcLock > 0: dec(recGcLock)
|
||||||
|
|
||||||
|
proc GC_setStrategy(strategy: TGC_Strategy) =
|
||||||
|
case strategy
|
||||||
|
of gcThroughput: nil
|
||||||
|
of gcResponsiveness: nil
|
||||||
|
of gcOptimizeSpace: nil
|
||||||
|
of gcOptimizeTime: nil
|
||||||
|
|
||||||
|
proc GC_enableMarkAndSweep() =
|
||||||
|
cycleThreshold = InitialThreshold
|
||||||
|
|
||||||
|
proc GC_disableMarkAndSweep() =
|
||||||
|
cycleThreshold = high(cycleThreshold)-1
|
||||||
|
# set to the max value to suppress the cycle detector
|
||||||
|
|
||||||
|
proc nextTry(h, maxHash: int): int {.inline.} =
|
||||||
|
result = ((5*h) + 1) and maxHash
|
||||||
|
# For any initial h in range(maxHash), repeating that maxHash times
|
||||||
|
# generates each int in range(maxHash) exactly once (see any text on
|
||||||
|
# random-number generation for proof).
|
||||||
|
|
||||||
|
# ------------------ Zero count table (ZCT) and any table (AT) -------------
|
||||||
|
|
||||||
|
# these values are for DL-malloc known for sure (and other allocators
|
||||||
|
# can only be worse):
|
||||||
|
when defined(useDL) or not defined(bcc):
|
||||||
|
const MemAlignment = 8 # minimal memory block that can be allocated
|
||||||
|
else:
|
||||||
|
const MemAlignment = 4 # Borland's memory manager is terrible!
|
||||||
|
|
||||||
|
const
|
||||||
|
BitsPerUnit = sizeof(int)*8
|
||||||
|
# a "unit" is a word, i.e. 4 bytes
|
||||||
|
# on a 32 bit system; I do not use the term "word" because under 32-bit
|
||||||
|
# Windows it is sometimes only 16 bits
|
||||||
|
|
||||||
|
BitsPerPage = PageSize div MemAlignment
|
||||||
|
UnitsPerPage = BitsPerPage div BitsPerUnit
|
||||||
|
# how many units do we need to describe a page:
|
||||||
|
# on 32 bit systems this is only 16 (!)
|
||||||
|
|
||||||
|
# this that has to equals zero, otherwise we have to round up UnitsPerPage:
|
||||||
|
when BitsPerPage mod BitsPerUnit != 0:
|
||||||
|
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
||||||
|
|
||||||
|
# ------------------- cell set handling ------------------------------
|
||||||
|
# A cellset consists of a hash table of page descriptors. A page
|
||||||
|
# descriptor has a bit for
|
||||||
|
# every Memalignment'th byte in the page.
|
||||||
|
# However, only bits corresponding to addresses that start memory blocks
|
||||||
|
# are set.
|
||||||
|
# Page descriptors are also linked to a list; the list
|
||||||
|
# is used for easy traversing of all page descriptors; this allows a
|
||||||
|
# fast iterator.
|
||||||
|
# We use a specialized hashing scheme; the formula is :
|
||||||
|
# hash = Page bitand max
|
||||||
|
# We use linear probing with the formular: (5*h)+1
|
||||||
|
# Thus we likely get no collisions at all if the pages are given us
|
||||||
|
# sequentially by the operating system!
|
||||||
|
type
|
||||||
|
PPageDesc = ptr TPageDesc
|
||||||
|
|
||||||
|
TBitIndex = range[0..UnitsPerPage-1]
|
||||||
|
|
||||||
|
TPageDesc = record
|
||||||
|
next: PPageDesc # all nodes are connected with this pointer
|
||||||
|
key: TAddress # start address at bit 0
|
||||||
|
bits: array[TBitIndex, int] # a bit vector
|
||||||
|
|
||||||
|
PPageDescArray = ptr array[0..1000_000, PPageDesc]
|
||||||
|
TCellSet = record
|
||||||
|
counter, max: int
|
||||||
|
head: PPageDesc
|
||||||
|
data: PPageDescArray
|
||||||
|
|
||||||
|
const
|
||||||
|
InitCellSetSize = 1024 # must be a power of two!
|
||||||
|
|
||||||
|
proc CellSetInit(s: var TCellSet) =
|
||||||
|
s.data = cast[PPageDescArray](gcAlloc(InitCellSetSize * sizeof(PPageDesc)))
|
||||||
|
s.max = InitCellSetSize-1
|
||||||
|
s.counter = 0
|
||||||
|
s.head = nil
|
||||||
|
|
||||||
|
proc CellSetDeinit(s: var TCellSet) =
|
||||||
|
var it = s.head
|
||||||
|
while it != nil:
|
||||||
|
var n = it.next
|
||||||
|
dealloc(it)
|
||||||
|
it = n
|
||||||
|
s.head = nil # play it safe here
|
||||||
|
dealloc(s.data)
|
||||||
|
s.data = nil
|
||||||
|
s.counter = 0
|
||||||
|
|
||||||
|
proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
|
||||||
|
var h = cast[int](key) and t.max
|
||||||
|
while t.data[h] != nil:
|
||||||
|
if t.data[h].key == key: return t.data[h]
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
proc CellSetRawInsert(t: TCellSet, data: PPageDescArray,
|
||||||
|
desc: PPageDesc) =
|
||||||
|
var h = cast[int](desc.key) and t.max
|
||||||
|
while data[h] != nil:
|
||||||
|
assert(data[h] != desc)
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
assert(data[h] == nil)
|
||||||
|
data[h] = desc
|
||||||
|
|
||||||
|
proc CellSetEnlarge(t: var TCellSet) =
|
||||||
|
var
|
||||||
|
n: PPageDescArray
|
||||||
|
oldMax = t.max
|
||||||
|
t.max = ((t.max+1)*2)-1
|
||||||
|
n = cast[PPageDescArray](gcAlloc((t.max + 1) * sizeof(PPageDesc)))
|
||||||
|
for i in 0 .. oldmax:
|
||||||
|
if t.data[i] != nil:
|
||||||
|
CellSetRawInsert(t, n, t.data[i])
|
||||||
|
dealloc(t.data)
|
||||||
|
t.data = n
|
||||||
|
|
||||||
|
proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
|
||||||
|
var h = cast[int](key) and t.max
|
||||||
|
while true:
|
||||||
|
var x = t.data[h]
|
||||||
|
if x == nil: break
|
||||||
|
if x.key == key: return x
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
|
||||||
|
if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t)
|
||||||
|
inc(t.counter)
|
||||||
|
h = cast[int](key) and t.max
|
||||||
|
while t.data[h] != nil: h = nextTry(h, t.max)
|
||||||
|
assert(t.data[h] == nil)
|
||||||
|
# the new page descriptor goes into result
|
||||||
|
result = cast[PPageDesc](gcAlloc(sizeof(TPageDesc)))
|
||||||
|
result.next = t.head
|
||||||
|
result.key = key
|
||||||
|
t.head = result
|
||||||
|
t.data[h] = result
|
||||||
|
|
||||||
|
# ---------- slightly higher level procs ----------------------------------
|
||||||
|
|
||||||
|
proc in_Operator(s: TCellSet, cell: PCell): bool =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetGet(s, u /% PageSize)
|
||||||
|
if t != nil:
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
|
|
||||||
|
proc incl(s: var TCellSet, cell: PCell) =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetPut(s, u /% PageSize)
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or
|
||||||
|
(1 shl (u %% BitsPerUnit))
|
||||||
|
|
||||||
|
proc excl(s: var TCellSet, cell: PCell) =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetGet(s, u /% PageSize)
|
||||||
|
if t != nil:
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
t.bits[u /% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and
|
||||||
|
not (1 shl (u %% BitsPerUnit)))
|
||||||
|
|
||||||
|
iterator elements(t: TCellSet): PCell {.inline.} =
|
||||||
|
# while traversing it is forbidden to add pointers to the tree!
|
||||||
|
var r = t.head
|
||||||
|
while r != nil:
|
||||||
|
var i = 0
|
||||||
|
while i <= high(r.bits):
|
||||||
|
var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
|
||||||
|
# modifying operations are not allowed during traversation
|
||||||
|
var j = 0
|
||||||
|
while w != 0: # test all remaining bits for zero
|
||||||
|
if (w and 1) != 0: # the bit is set!
|
||||||
|
yield cast[PCell]((r.key *% PageSize) +%
|
||||||
|
(i*%BitsPerUnit+%j) *% MemAlignment)
|
||||||
|
inc(j)
|
||||||
|
w = w shr 1
|
||||||
|
inc(i)
|
||||||
|
r = r.next
|
||||||
|
|
||||||
|
# --------------- end of Cellset routines -------------------------------------
|
||||||
|
|
||||||
|
proc testPageDescs() =
|
||||||
|
var root: TCellSet
|
||||||
|
CellSetInit(root)
|
||||||
|
var u = 10_000
|
||||||
|
while u <= 20_000:
|
||||||
|
incl(root, cast[PCell](u))
|
||||||
|
inc(u, 8)
|
||||||
|
for cell in elements(root):
|
||||||
|
c_fprintf(c_stdout, "%ld\n", cast[int](cell))
|
||||||
|
|
||||||
|
# testPageDescs()
|
||||||
|
|
||||||
|
when defined(debugGC):
|
||||||
|
proc writeCell(msg: CString, c: PCell) =
|
||||||
|
c_fprintf(c_stdout, "%s: %p\n", msg, c)
|
||||||
|
proc writePtr(msg: CString, p: Pointer) =
|
||||||
|
c_fprintf(c_stdout, "%s: %p\n", msg, p)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
PStackCells = ptr array[0..1000_0000, PCell]
|
||||||
|
TCountTables = record # this contains the zero count and
|
||||||
|
# non-zero count table
|
||||||
|
mask: TAddress # mask for fast pointer detection
|
||||||
|
zct: TCellSet # the zero count table
|
||||||
|
at: TCellSet # a table that contains all references
|
||||||
|
newAT: TCellSet
|
||||||
|
newZCT: TCellSet
|
||||||
|
stackCells: PStackCells # cells that need to be decremented because they
|
||||||
|
# are in the hardware stack; a cell may occur
|
||||||
|
# several times in this data structure
|
||||||
|
stackLen, stackMax: int # for managing the stack cells
|
||||||
|
|
||||||
|
proc addStackCell(ct: var TCountTables, cell: PCell) =
|
||||||
|
if ct.stackLen >= ct.stackMax:
|
||||||
|
ct.stackMax = ct.stackMax * 3 div 2
|
||||||
|
ct.stackCells = cast[PStackCells](realloc(ct.stackCells, ct.stackMax *
|
||||||
|
sizeof(PCell)))
|
||||||
|
if ct.stackCells == nil: raiseOutOfMem()
|
||||||
|
ct.stackCells[ct.stackLen] = cell
|
||||||
|
inc(ct.stackLen)
|
||||||
|
|
||||||
|
var
|
||||||
|
stackBottom: pointer
|
||||||
|
ct: TCountTables
|
||||||
|
|
||||||
|
proc GC_invariant(): bool =
|
||||||
|
result = True
|
||||||
|
when stressGC:
|
||||||
|
if recGcLock == 0:
|
||||||
|
GC_disable()
|
||||||
|
for cell in elements(ct.at):
|
||||||
|
var t = cell.typ # getCellType(cell)
|
||||||
|
if t == nil or t.kind notin {tySequence, tyString, tyRef}:
|
||||||
|
writeCell("corrupt cell?", cell)
|
||||||
|
result = false
|
||||||
|
GC_enable()
|
||||||
|
|
||||||
|
when stressGC:
|
||||||
|
proc GCdebugHook() =
|
||||||
|
if not GC_invariant():
|
||||||
|
assert(false)
|
||||||
|
|
||||||
|
dbgLineHook = GCdebugHook
|
||||||
|
|
||||||
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
if cell.typ.finalizer != nil:
|
||||||
|
# the finalizer could invoke something that
|
||||||
|
# allocates memory; this could trigger a garbage
|
||||||
|
# collection. Since we are already collecting we
|
||||||
|
# prevend recursive entering here by a lock.
|
||||||
|
# XXX: we should set the cell's children to nil!
|
||||||
|
inc(recGcLock)
|
||||||
|
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
|
dec(recGcLock)
|
||||||
|
|
||||||
|
when defined(nimSize):
|
||||||
|
memUsed = memUsed - nimSize(cell)
|
||||||
|
else:
|
||||||
|
memUsed = memUsed - cell.typ.size
|
||||||
|
|
||||||
|
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
|
||||||
|
stackBottom = theStackBottom
|
||||||
|
|
||||||
|
proc initGC() =
|
||||||
|
# init the rt
|
||||||
|
CellSetInit(ct.zct)
|
||||||
|
CellSetInit(ct.at)
|
||||||
|
ct.stackLen = 0
|
||||||
|
ct.stackMax = 255
|
||||||
|
ct.stackCells = cast[PStackCells](gcAlloc((ct.stackMax+1) * sizeof(PCell)))
|
||||||
|
ct.mask = 0
|
||||||
|
new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
|
||||||
|
assert(GC_invariant())
|
||||||
|
|
||||||
|
# forward declarations:
|
||||||
|
proc collectCT(ct: var TCountTables)
|
||||||
|
proc IsOnStack(p: pointer): bool
|
||||||
|
proc forAllChildren(cell: PCell, op: TWalkOp)
|
||||||
|
proc collectCycles()
|
||||||
|
|
||||||
|
proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
|
||||||
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
|
proc outputCell(c: PCell) =
|
||||||
|
inc(recGcLock)
|
||||||
|
write(stdout, reprAny(cellToUsr(c), c.typ))
|
||||||
|
dec(recGcLock)
|
||||||
|
|
||||||
|
proc writeGraph() =
|
||||||
|
{.checkpoint.}
|
||||||
|
block:
|
||||||
|
inc(recGcLock)
|
||||||
|
for c in elements(ct.AT): outputCell(c)
|
||||||
|
dec(recGcLock)
|
||||||
|
|
||||||
|
proc checkRefc(): bool =
|
||||||
|
if recGcLock >= 1: return true # prevent endless recursion
|
||||||
|
inc(recGcLock)
|
||||||
|
result = True
|
||||||
|
# set counters back to zero:
|
||||||
|
for c in elements(ct.AT):
|
||||||
|
c.drefc = 0
|
||||||
|
for c in elements(ct.AT):
|
||||||
|
forAllChildren(c, waDebugIncRef)
|
||||||
|
for c in elements(ct.AT):
|
||||||
|
if c.drefc > c.refcount - c.stackcount:
|
||||||
|
result = false # failed
|
||||||
|
c_fprintf(c_stdout,
|
||||||
|
"broken cell: %p, refc: %ld, stack: %ld, real: %ld\n",
|
||||||
|
c, c.refcount, c.stackcount, c.drefc)
|
||||||
|
dec(recGcLock)
|
||||||
|
|
||||||
|
proc seqCheck(cell: PCell): bool =
|
||||||
|
assert(cell.typ != nil)
|
||||||
|
if cell.typ.kind in {tySequence, tyString}:
|
||||||
|
result = cell.refcount - cell.stackcount <= 1
|
||||||
|
else:
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc decRef(cell: PCell) {.inline.} =
|
||||||
|
assert(cell in ct.AT)
|
||||||
|
when defined(debugGC):
|
||||||
|
if cell.refcount == 0:
|
||||||
|
writePtr("decref broken", cellToUsr(cell))
|
||||||
|
assert(cell.refcount > 0) # this should be the case!
|
||||||
|
assert(seqCheck(cell))
|
||||||
|
dec(cell.refcount)
|
||||||
|
if cell.refcount == 0:
|
||||||
|
incl(ct.zct, cell)
|
||||||
|
|
||||||
|
proc incRef(cell: PCell) {.inline.} =
|
||||||
|
assert(seqCheck(cell))
|
||||||
|
inc(cell.refcount)
|
||||||
|
|
||||||
|
proc asgnRef(dest: ppointer, src: pointer) =
|
||||||
|
# the code generator calls this proc!
|
||||||
|
assert(not isOnStack(dest))
|
||||||
|
# BUGFIX: first incRef then decRef!
|
||||||
|
if src != nil: incRef(usrToCell(src))
|
||||||
|
if dest^ != nil: decRef(usrToCell(dest^))
|
||||||
|
dest^ = src
|
||||||
|
#assert(checkRefc())
|
||||||
|
|
||||||
|
proc unsureAsgnRef(dest: ppointer, src: pointer) =
|
||||||
|
if not IsOnStack(dest):
|
||||||
|
if src != nil: incRef(usrToCell(src))
|
||||||
|
if dest^ != nil: decRef(usrToCell(dest^))
|
||||||
|
dest^ = src
|
||||||
|
#assert(checkRefc())
|
||||||
|
|
||||||
|
proc restore(cell: PCell) =
|
||||||
|
if cell notin ct.newAT:
|
||||||
|
incl(ct.newAT, Cell)
|
||||||
|
forAllChildren(cell, waCycleIncRef)
|
||||||
|
|
||||||
|
proc doOperation(p: pointer, op: TWalkOp) =
|
||||||
|
if p == nil: return
|
||||||
|
var cell: PCell = usrToCell(p)
|
||||||
|
assert(cell != nil)
|
||||||
|
case op # faster than function pointers because of easy prediction
|
||||||
|
of waNone: assert(false)
|
||||||
|
of waRelease: decRef(cell) # DEAD CODE!
|
||||||
|
of waZctDecRef:
|
||||||
|
assert(cell.refcount > 0)
|
||||||
|
assert(seqCheck(cell))
|
||||||
|
dec(cell.refcount)
|
||||||
|
if cell.refcount == 0:
|
||||||
|
incl(ct.newZCT, cell)
|
||||||
|
of waCycleDecRef:
|
||||||
|
assert(cell.refcount != 0)
|
||||||
|
dec(cell.refcount)
|
||||||
|
of waCycleIncRef:
|
||||||
|
inc(cell.refcount) # restore proper reference counts!
|
||||||
|
restore(cell)
|
||||||
|
of waDebugIncRef:
|
||||||
|
inc(cell.drefc)
|
||||||
|
|
||||||
|
type
|
||||||
|
TByteArray = array[0..1000_0000, byte]
|
||||||
|
PByte = ptr TByteArray
|
||||||
|
PString = ptr string
|
||||||
|
|
||||||
|
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
|
||||||
|
|
||||||
|
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
|
||||||
|
assert(n.kind == nkCase)
|
||||||
|
var d: int32
|
||||||
|
var a = cast[TAddress](aa)
|
||||||
|
case n.typ.size
|
||||||
|
of 1: d = toU32(cast[ptr int8](a +% n.offset)^)
|
||||||
|
of 2: d = toU32(cast[ptr int16](a +% n.offset)^)
|
||||||
|
of 4: d = toU32(cast[ptr int32](a +% n.offset)^)
|
||||||
|
else: assert(false)
|
||||||
|
return int(d)
|
||||||
|
|
||||||
|
proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
|
||||||
|
var discr = getDiscriminant(aa, n)
|
||||||
|
if discr <% n.len:
|
||||||
|
result = n.sons[discr]
|
||||||
|
if result == nil: result = n.sons[n.len]
|
||||||
|
# n.sons[n.len] contains the ``else`` part (but may be nil)
|
||||||
|
else:
|
||||||
|
result = n.sons[n.len]
|
||||||
|
|
||||||
|
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
|
||||||
|
var
|
||||||
|
d = cast[TAddress](dest)
|
||||||
|
case n.kind
|
||||||
|
of nkNone: assert(false)
|
||||||
|
of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
|
||||||
|
of nkList:
|
||||||
|
for i in 0..n.len-1: forAllSlotsAux(dest, n.sons[i], op)
|
||||||
|
of nkCase:
|
||||||
|
var m = selectBranch(dest, n)
|
||||||
|
if m != nil: forAllSlotsAux(dest, m, op)
|
||||||
|
|
||||||
|
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
|
||||||
|
var
|
||||||
|
d = cast[TAddress](dest)
|
||||||
|
if dest == nil: return # nothing to do
|
||||||
|
case mt.Kind
|
||||||
|
of tyArray, tyArrayConstr, tyOpenArray:
|
||||||
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
|
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
|
||||||
|
of tyRef, tyString, tySequence: # leaf:
|
||||||
|
doOperation(cast[ppointer](d)^, op)
|
||||||
|
of tyRecord, tyObject, tyTuple:
|
||||||
|
forAllSlotsAux(dest, mt.node, op)
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
proc forAllChildren(cell: PCell, op: TWalkOp) =
|
||||||
|
assert(cell != nil)
|
||||||
|
when defined(debugGC):
|
||||||
|
if cell.typ == nil:
|
||||||
|
writeCell("cell has no type descriptor", cell)
|
||||||
|
assert(cell.typ != nil)
|
||||||
|
case cell.typ.Kind
|
||||||
|
of tyRef: # common case
|
||||||
|
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||||
|
of tySequence:
|
||||||
|
var d = cast[TAddress](cellToUsr(cell))
|
||||||
|
var s = cast[PGenericSeq](d)
|
||||||
|
if s != nil: # BUGFIX
|
||||||
|
for i in 0..s.len-1:
|
||||||
|
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
|
||||||
|
GenericSeqSize), cell.typ.base, op)
|
||||||
|
of tyString: nil
|
||||||
|
else: assert(false)
|
||||||
|
|
||||||
|
proc checkCollection() {.inline.} =
|
||||||
|
# checks if a collection should be done
|
||||||
|
if recGcLock == 0:
|
||||||
|
if memUsed >= rcThreshold or stressGC:
|
||||||
|
collectCT(ct)
|
||||||
|
when defined(debugGC):
|
||||||
|
write(stdout, "threshold is now: ")
|
||||||
|
writeln(stdout, rcThreshold)
|
||||||
|
|
||||||
|
proc newObj(typ: PNimType, size: int): pointer =
|
||||||
|
# generates a new object and sets its reference counter to 0
|
||||||
|
var
|
||||||
|
res: PCell
|
||||||
|
assert(typ.kind in {tyRef, tyString, tySequence})
|
||||||
|
# check if we have to collect:
|
||||||
|
checkCollection()
|
||||||
|
res = cast[PCell](Alloc0(size + sizeof(TCell)))
|
||||||
|
if res == nil: raiseOutOfMem()
|
||||||
|
when defined(nimSize):
|
||||||
|
memUsed = memUsed + nimSize(res)
|
||||||
|
else:
|
||||||
|
memUsed = memUsed + size
|
||||||
|
|
||||||
|
res.refcount = 0
|
||||||
|
# now it is buffered in the ZCT
|
||||||
|
res.typ = typ
|
||||||
|
incl(ct.zct, res) # its refcount is zero, so add it to the ZCT
|
||||||
|
incl(ct.at, res) # add it to the any table too
|
||||||
|
ct.mask = ct.mask or cast[TAddress](res)
|
||||||
|
when defined(debugGC):
|
||||||
|
writeCell("new cell", res)
|
||||||
|
assert(gcInvariant())
|
||||||
|
result = cellToUsr(res)
|
||||||
|
|
||||||
|
proc newSeq(typ: PNimType, len: int): pointer =
|
||||||
|
# XXX: overflow checks!
|
||||||
|
result = newObj(typ, len * typ.base.size + GenericSeqSize)
|
||||||
|
cast[PGenericSeq](result).len = len
|
||||||
|
cast[PGenericSeq](result).space = len
|
||||||
|
|
||||||
|
proc growObj(old: pointer, newsize: int): pointer =
|
||||||
|
var
|
||||||
|
res, ol: PCell
|
||||||
|
checkCollection()
|
||||||
|
ol = usrToCell(old)
|
||||||
|
assert(ol.typ.kind in {tyString, tySequence})
|
||||||
|
assert(seqCheck(ol))
|
||||||
|
when defined(nimSize):
|
||||||
|
memUsed = memUsed - nimSize(ol)
|
||||||
|
else:
|
||||||
|
memUsed = memUsed - ol.size # this is not exact
|
||||||
|
# pity that we don't know the old size
|
||||||
|
res = cast[PCell](realloc(ol, newsize + sizeof(TCell)))
|
||||||
|
when defined(nimSize):
|
||||||
|
memUsed = memUsed + nimSize(res)
|
||||||
|
else:
|
||||||
|
memUsed = memUsed + newsize
|
||||||
|
|
||||||
|
if res != ol:
|
||||||
|
if res == nil: raiseOutOfMem()
|
||||||
|
excl(ct.zct, ol) # remove old pointer in any case:
|
||||||
|
# It may have a refcount > 0 and is still in the ZCT.
|
||||||
|
# So do it safe here and remove it anyway.
|
||||||
|
excl(ct.at, ol)
|
||||||
|
if res.refcount == 0:
|
||||||
|
# store new pointer in ZCT, if refcount == 0:
|
||||||
|
incl(ct.zct, res)
|
||||||
|
incl(ct.at, res)
|
||||||
|
ct.mask = ct.mask or cast[TAddress](res)
|
||||||
|
when defined(debugGC):
|
||||||
|
writeCell("growObj old cell", ol)
|
||||||
|
writeCell("growObj new cell", res)
|
||||||
|
result = cellToUsr(res)
|
||||||
|
#assert(checkRefc())
|
||||||
|
|
||||||
|
proc collectCycles() =
|
||||||
|
when defined(debugGC):
|
||||||
|
echo("collecting cycles!\n")
|
||||||
|
|
||||||
|
# step 1: pretend that any node is dead
|
||||||
|
for c in elements(ct.at):
|
||||||
|
forallChildren(c, waCycleDecRef)
|
||||||
|
CellSetInit(ct.newAt)
|
||||||
|
# step 2: restore life cells
|
||||||
|
for c in elements(ct.at):
|
||||||
|
if c.refcount > 0: restore(c)
|
||||||
|
# step 3: free dead cells:
|
||||||
|
for cell in elements(ct.at):
|
||||||
|
if cell.refcount == 0:
|
||||||
|
assert(cell notin ct.zct)
|
||||||
|
# We free an object that is part of a cycle here. Its children
|
||||||
|
# may have been freed already. Thus the finalizer could access
|
||||||
|
# garbage. To handle this case properly we need two passes for
|
||||||
|
# freeing here which is too expensive. We just don't call the
|
||||||
|
# finalizer for now. YYY: Any better ideas?
|
||||||
|
prepareDealloc(cell)
|
||||||
|
dealloc(cell)
|
||||||
|
when defined(debugGC):
|
||||||
|
writeCell("cycle collector dealloc cell", cell)
|
||||||
|
CellSetDeinit(ct.at)
|
||||||
|
ct.at = ct.newAt
|
||||||
|
#ct.newAt = nil
|
||||||
|
|
||||||
|
proc gcMark(p: pointer) =
|
||||||
|
# the addresses are not as objects on the stack, so turn them to objects:
|
||||||
|
var cell = usrToCell(p)
|
||||||
|
var c = cast[TAddress](cell)
|
||||||
|
if ((c and ct.mask) == c) and cell in ct.at:
|
||||||
|
# is the page that p "points to" in the AT? (All allocated pages are
|
||||||
|
# always in the AT)
|
||||||
|
inc(cell.refcount)
|
||||||
|
inc(cell.stackcount)
|
||||||
|
addStackCell(ct, cell)
|
||||||
|
|
||||||
|
proc unmarkStackAndRegisters() =
|
||||||
|
for i in 0 .. ct.stackLen-1:
|
||||||
|
var cell = ct.stackCells[i]
|
||||||
|
assert(cell.refcount > 0)
|
||||||
|
when defined(debugGC):
|
||||||
|
if cell.stackcount == 0:
|
||||||
|
writeGraph()
|
||||||
|
writePtr("broken stackcount", cellToUsr(cell))
|
||||||
|
assert(cell.stackcount > 0)
|
||||||
|
dec(cell.refcount)
|
||||||
|
dec(cell.stackcount)
|
||||||
|
if cell.refcount == 0:
|
||||||
|
incl(ct.zct, cell)
|
||||||
|
ct.stackLen = 0 # reset to zero
|
||||||
|
|
||||||
|
# ----------------- stack management --------------------------------------
|
||||||
|
# inspired from Smart Eiffel (c)
|
||||||
|
|
||||||
|
proc stackSize(): int =
|
||||||
|
var stackTop: array[0..1, pointer]
|
||||||
|
result = abs(cast[int](addr(stackTop[0])) - cast[int](stackBottom))
|
||||||
|
|
||||||
|
when defined(sparc): # For SPARC architecture.
|
||||||
|
|
||||||
|
proc isOnStack(p: pointer): bool =
|
||||||
|
var
|
||||||
|
stackTop: array[0..1, pointer]
|
||||||
|
result = p >= addr(stackTop[0]) and p <= stackBottom
|
||||||
|
|
||||||
|
proc markStackAndRegisters() =
|
||||||
|
when defined(sparcv9):
|
||||||
|
asm " flushw"
|
||||||
|
else:
|
||||||
|
asm " ta 0x3 ! ST_FLUSH_WINDOWS"
|
||||||
|
|
||||||
|
var
|
||||||
|
max = stackBottom
|
||||||
|
sp: PPointer
|
||||||
|
stackTop: array[0..1, pointer]
|
||||||
|
stackTop[0] = nil
|
||||||
|
stackTop[1] = nil
|
||||||
|
sp = addr(stackTop[0])
|
||||||
|
# Addresses decrease as the stack grows.
|
||||||
|
while sp <= max:
|
||||||
|
gcMark(sp^)
|
||||||
|
sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
|
||||||
|
|
||||||
|
elif defined(ELATE):
|
||||||
|
{.error: "stack marking code has to be written for this architecture".}
|
||||||
|
|
||||||
|
elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
|
||||||
|
defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generic code for architectures where addresses increase as the stack grows.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc isOnStack(p: pointer): bool =
|
||||||
|
var
|
||||||
|
stackTop: array[0..1, pointer]
|
||||||
|
result = p <= addr(stackTop[0]) and p >= stackBottom
|
||||||
|
|
||||||
|
var
|
||||||
|
jmpbufSize {.importc: "sizeof(jmp_buf)".}: int
|
||||||
|
# a little hack to get the size of a TJmpBuf in the generated C code
|
||||||
|
# in a platform independant way
|
||||||
|
|
||||||
|
proc markStackAndRegisters() =
|
||||||
|
var
|
||||||
|
max = stackBottom
|
||||||
|
registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
|
||||||
|
sp: PPointer # Used to traverse the stack and registers assuming
|
||||||
|
# that `setjmp' will save registers in the C stack.
|
||||||
|
c_setjmp(registers) # To fill the C stack with registers.
|
||||||
|
sp = cast[ppointer](cast[TAddress](addr(registers)) +%
|
||||||
|
jmpbufSize -% sizeof(pointer))
|
||||||
|
# sp will traverse the JMP_BUF as well (jmp_buf size is added,
|
||||||
|
# otherwise sp would be below the registers structure).
|
||||||
|
while sp >= max:
|
||||||
|
gcMark(sp^)
|
||||||
|
sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generic code for architectures where addresses decrease as the stack grows.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
proc isOnStack(p: pointer): bool =
|
||||||
|
var
|
||||||
|
stackTop: array [0..1, pointer]
|
||||||
|
result = p >= addr(stackTop[0]) and p <= stackBottom
|
||||||
|
|
||||||
|
proc markStackAndRegisters() =
|
||||||
|
var
|
||||||
|
max = stackBottom
|
||||||
|
registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
|
||||||
|
sp: PPointer # Used to traverse the stack and registers assuming
|
||||||
|
# that `setjmp' will save registers in the C stack.
|
||||||
|
c_setjmp(registers) # To fill the C stack with registers.
|
||||||
|
sp = cast[ppointer](addr(registers))
|
||||||
|
while sp <= max:
|
||||||
|
gcMark(sp^)
|
||||||
|
sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# end of non-portable code
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc CollectZCT =
|
||||||
|
CellSetInit(ct.newZCT)
|
||||||
|
for c in elements(ct.zct):
|
||||||
|
if c.refcount == 0:
|
||||||
|
# if != 0 the reference count has been increased, so this does not
|
||||||
|
# belong to the ZCT. We simply do nothing - it won't appear in the newZCT
|
||||||
|
# anyway.
|
||||||
|
# We are about to free the object, call the finalizer BEFORE its
|
||||||
|
# children are deleted as well, because otherwise the finalizer may
|
||||||
|
# access invalid memory. This is done by prepareDealloc():
|
||||||
|
prepareDealloc(c)
|
||||||
|
forAllChildren(c, waZctDecRef)
|
||||||
|
assert(c.refcount == 0) # should still be zero
|
||||||
|
excl(ct.at, c)
|
||||||
|
excl(ct.newZCT, c) # BUGFIX
|
||||||
|
when defined(debugGC):
|
||||||
|
writeCell("zct dealloc cell", c)
|
||||||
|
dealloc(c)
|
||||||
|
CellSetDeinit(ct.zct)
|
||||||
|
ct.zct = ct.newZCT
|
||||||
|
#ct.newZCT = nil
|
||||||
|
|
||||||
|
proc collectCT(ct: var TCountTables) =
|
||||||
|
when defined(debugGC):
|
||||||
|
c_fprintf(c_stdout, "collecting zero count table; stack size: %ld\n",
|
||||||
|
stackSize())
|
||||||
|
markStackAndRegisters()
|
||||||
|
assert(GC_invariant())
|
||||||
|
while True:
|
||||||
|
collectZCT()
|
||||||
|
if ct.zct.counter == 0: break
|
||||||
|
# ``counter`` counts the pages, but zero pages means zero cells
|
||||||
|
|
||||||
|
when defined(cycleGC):
|
||||||
|
# still over the cycle threshold?
|
||||||
|
if memUsed >= cycleThreshold or stressGC:
|
||||||
|
# collect the cyclic things:
|
||||||
|
assert(ct.zct.counter == 0)
|
||||||
|
assert(GC_invariant())
|
||||||
|
collectCycles()
|
||||||
|
|
||||||
|
# recompute the thresholds:
|
||||||
|
rcThreshold = (memUsed div RC_increase + 1) * RC_Increase
|
||||||
|
cycleThreshold = memUsed * cycleIncrease
|
||||||
|
|
||||||
|
assert(GC_invariant())
|
||||||
|
unmarkStackAndRegisters()
|
||||||
|
|
||||||
|
proc GC_fullCollect() =
|
||||||
|
var oldThreshold = cycleThreshold
|
||||||
|
cycleThreshold = 0 # forces cycle collection
|
||||||
|
collectCT(ct)
|
||||||
|
cycleThreshold = oldThreshold
|
||||||
51
lib/hti.nim
Executable file
51
lib/hti.nim
Executable file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
type # This should be he same as ast.TTypeKind
|
||||||
|
# some enum fields are not used at runtime
|
||||||
|
TNimKind = enum
|
||||||
|
tyNone, tyBool, tyChar,
|
||||||
|
tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr,
|
||||||
|
tyGeneric,
|
||||||
|
tyGenericInst,
|
||||||
|
tyGenericParam,
|
||||||
|
tyEnum, tyAnyEnum,
|
||||||
|
tyArray,
|
||||||
|
tyRecord,
|
||||||
|
tyObject,
|
||||||
|
tyTuple,
|
||||||
|
tySet,
|
||||||
|
tyRange,
|
||||||
|
tyPtr, tyRef,
|
||||||
|
tyVar,
|
||||||
|
tySequence,
|
||||||
|
tyProc,
|
||||||
|
tyPointer, tyOpenArray,
|
||||||
|
tyString, tyCString, tyForward,
|
||||||
|
tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
|
||||||
|
tyFloat, tyFloat32, tyFloat64, tyFloat128
|
||||||
|
|
||||||
|
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||||
|
TNimNode {.compilerproc.} = record
|
||||||
|
kind: TNimNodeKind
|
||||||
|
offset: int
|
||||||
|
typ: ptr TNimType
|
||||||
|
name: Cstring
|
||||||
|
len: int
|
||||||
|
sons: ptr array [0..0x7fff, ptr TNimNode]
|
||||||
|
|
||||||
|
TNimType {.compilerproc.} = record
|
||||||
|
size: int
|
||||||
|
kind: TNimKind
|
||||||
|
base: ptr TNimType
|
||||||
|
node: ptr TNimNode # valid for tyRecord, tyObject, tyTuple, tyEnum
|
||||||
|
finalizer: pointer # the finalizer for the type
|
||||||
|
PNimType = ptr TNimType
|
||||||
|
|
||||||
|
# node.len may be the ``first`` element of a set
|
||||||
70
lib/i386.asm.in
Executable file
70
lib/i386.asm.in
Executable file
|
|
@ -0,0 +1,70 @@
|
||||||
|
; This contains the CPU-dependant variants of some routines.
|
||||||
|
; (C) 2005 Andreas Rumpf
|
||||||
|
; This code was inspired by the Freepascal compiler's sources
|
||||||
|
; All routines here have the _cdecl calling convention because
|
||||||
|
; that is the only convention any C compiler supports.
|
||||||
|
|
||||||
|
\python{
|
||||||
|
# as usual I use my own preprocessor :-)
|
||||||
|
import os
|
||||||
|
|
||||||
|
def c(name):
|
||||||
|
if os.name == 'posix':
|
||||||
|
return name
|
||||||
|
else:
|
||||||
|
return "_" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
segment code
|
||||||
|
|
||||||
|
global \c{cpu_inc_locked}
|
||||||
|
global \c{cpu_dec_locked}
|
||||||
|
global \c{cpu_lock}
|
||||||
|
global \c{cpu_unlock}
|
||||||
|
|
||||||
|
\c{cpu_dec_locked}:
|
||||||
|
push ebp
|
||||||
|
mov ebp,esp
|
||||||
|
mov eax,[ebp+8] ; first parameter to function
|
||||||
|
lock dec dword [eax]
|
||||||
|
setz al
|
||||||
|
mov esp,ebp
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
\c{cpu_inc_locked}:
|
||||||
|
push ebp
|
||||||
|
mov ebp,esp
|
||||||
|
mov eax,[ebp+8] ; first parameter to function
|
||||||
|
lock inc dword [eax]
|
||||||
|
mov esp,ebp
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
; This code uses the highest bit of the RC to indicate that the RC is
|
||||||
|
; locked (spinlock).
|
||||||
|
\c{cpu_lock}
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
mov eax, [ebp+8] ; first parameter to function
|
||||||
|
mov edx, [eax] ; load RC
|
||||||
|
or edx, 0x80000000 ; set highest bit
|
||||||
|
spin:
|
||||||
|
xchg [eax], edx ; atomic instruction!
|
||||||
|
pause ; wait a few cycles
|
||||||
|
and edx, 0x80000000 ; mask highest bit
|
||||||
|
jnz spin
|
||||||
|
mov esp, ebp
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
\c{cpu_unlock}
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
mov eax, [ebp+8] ; first parameter to function
|
||||||
|
mov edx, [eax] ; load RC
|
||||||
|
and edx, 0x7FFFFFFF ; unset highest bit
|
||||||
|
xchg [eax], edx ; atomic instruction!
|
||||||
|
mov esp, ebp
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
72
lib/int64s.nim
Executable file
72
lib/int64s.nim
Executable file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# 64 bit integers for platforms that don't have those
|
||||||
|
|
||||||
|
type
|
||||||
|
IInt64 = record # "internal" int64
|
||||||
|
lo, hi: int32
|
||||||
|
|
||||||
|
proc cmpI64(x, y: IInt64): int32 {.compilerproc.} =
|
||||||
|
result = x.hi -% y.hi
|
||||||
|
if result == 0: result = x.lo -% y.lo
|
||||||
|
|
||||||
|
proc addI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result = x
|
||||||
|
result.lo = result.lo +% y.lo
|
||||||
|
result.hi = result.hi +% y.hi
|
||||||
|
if y.lo > 0 and result.lo < y.lo:
|
||||||
|
inc(result.hi)
|
||||||
|
elif y.lo < 0 and result.lo > y.lo:
|
||||||
|
dec(result.hi)
|
||||||
|
|
||||||
|
proc subI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result = x
|
||||||
|
result.lo = result.lo -% y.lo
|
||||||
|
result.hi = result.hi -% y.hi
|
||||||
|
if y.lo > 0 and result.lo < y.lo:
|
||||||
|
inc(result.hi)
|
||||||
|
elif y.lo < 0 and result.lo > y.lo:
|
||||||
|
dec(result.hi)
|
||||||
|
|
||||||
|
proc mulI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result.lo = x.lo *% y.lo
|
||||||
|
result.hi = y.hi *% y.hi
|
||||||
|
if y.lo > 0 and result.lo < y.lo:
|
||||||
|
inc(result.hi)
|
||||||
|
elif y.lo < 0 and result.lo > y.lo:
|
||||||
|
dec(result.hi)
|
||||||
|
|
||||||
|
proc divI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
# XXX: to implement
|
||||||
|
|
||||||
|
proc modI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
# XXX: to implement
|
||||||
|
|
||||||
|
proc bitandI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result.hi = x.hi and y.hi
|
||||||
|
result.lo = x.lo and y.lo
|
||||||
|
|
||||||
|
proc bitorI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result.hi = x.hi or y.hi
|
||||||
|
result.lo = x.lo or y.lo
|
||||||
|
|
||||||
|
proc bitxorI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result.hi = x.hi xor y.hi
|
||||||
|
result.lo = x.lo xor y.lo
|
||||||
|
|
||||||
|
proc bitnotI64(x: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
result.lo = not x.lo
|
||||||
|
result.hi = not x.hi
|
||||||
|
|
||||||
|
proc shlI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
# XXX: to implement
|
||||||
|
|
||||||
|
proc shrI64(x, y: IInt64): IInt64 {.compilerproc.} =
|
||||||
|
# XXX: to implement
|
||||||
502
lib/lgpl.txt
Executable file
502
lib/lgpl.txt
Executable file
|
|
@ -0,0 +1,502 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
||||||
|
|
||||||
|
|
||||||
18
lib/locks.nim
Executable file
18
lib/locks.nim
Executable file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Simple platform dependant lock implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
TSimpleLock = pointer
|
||||||
|
|
||||||
|
proc initLock(s: TSimpleLock)
|
||||||
|
proc deinitLock(s: TSimpleLock)
|
||||||
|
proc lock(s: TSimpleLock)
|
||||||
|
proc unlock(s: TSimpleLock)
|
||||||
131
lib/math.nim
Executable file
131
lib/math.nim
Executable file
|
|
@ -0,0 +1,131 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# math routines
|
||||||
|
|
||||||
|
# interface
|
||||||
|
|
||||||
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
{.push checks:off, line_dir:off, stack_trace:off.}
|
||||||
|
|
||||||
|
proc nextPowerOfTwo*(x: int): int
|
||||||
|
## returns the nearest power of two, so that
|
||||||
|
## result**2 >= x > (result-1)**2.
|
||||||
|
proc isPowerOfTwo*(x: int): bool {.noSideEffect.}
|
||||||
|
## returns true, if x is a power of two, false otherwise.
|
||||||
|
## Negative numbers are not a power of two.
|
||||||
|
proc countBits*(n: int32): int {.noSideEffect.}
|
||||||
|
## counts the set bits in `n`.
|
||||||
|
|
||||||
|
proc random*(max: int): int
|
||||||
|
## returns a random number in the range 0..max-1. The sequence of
|
||||||
|
## random number is always the same, unless `randomize` is called
|
||||||
|
## which initializes the random number generator with a "random"
|
||||||
|
## number, i.e. a tickcount.
|
||||||
|
proc randomize*()
|
||||||
|
## initializes the random number generator with a "random"
|
||||||
|
## number, i.e. a tickcount.
|
||||||
|
|
||||||
|
proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
|
||||||
|
## computes the square root of `x`.
|
||||||
|
|
||||||
|
proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
|
||||||
|
## computes ln(x).
|
||||||
|
proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
|
||||||
|
## computes e**x.
|
||||||
|
|
||||||
|
proc frexp*(x: float, exponent: var int): float {.
|
||||||
|
importc: "frexp", header: "<math.h>".}
|
||||||
|
## Split a number into mantissa and exponent.
|
||||||
|
## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
|
||||||
|
## and less than 1) and the integer value n such that `x` (the original
|
||||||
|
## float value) equals m * 2**n. frexp stores n in `exponent` and returns
|
||||||
|
## m.
|
||||||
|
|
||||||
|
proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
|
||||||
|
proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
|
||||||
|
proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
|
||||||
|
proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
|
||||||
|
## Calculate the arc tangent of `y` / `x`.
|
||||||
|
## `atan2` returns the arc tangent of `y` / `x`; it produces correct
|
||||||
|
## results even when the resulting angle is near pi/2 or -pi/2
|
||||||
|
## (`x` near 0).
|
||||||
|
|
||||||
|
proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
|
||||||
|
proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
|
||||||
|
proc hypot*(x: float): float {.importc: "hypot", header: "<math.h>".}
|
||||||
|
proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
|
||||||
|
proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
|
||||||
|
proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
|
||||||
|
proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
|
||||||
|
proc pow*(x, y: float): float {.importc: "pos", header: "<math.h>".}
|
||||||
|
## computes x to power raised of y.
|
||||||
|
|
||||||
|
type
|
||||||
|
TFloatClass* = enum ## describes the class a floating point value belongs to.
|
||||||
|
## This is the type that is returned by `classify`.
|
||||||
|
fcNormal, ## value is an ordinary nonzero floating point value
|
||||||
|
fcSubnormal, ## value is a subnormal (a very small) floating point value
|
||||||
|
fcZero, ## value is zero
|
||||||
|
fcNegZero, ## value is the negative zero
|
||||||
|
fcNan, ## value is Not-A-Number (NAN)
|
||||||
|
fcInf, ## value is positive infinity
|
||||||
|
fcNegInf ## value is negative infinity
|
||||||
|
|
||||||
|
proc classify*(x: float): TFloatClass
|
||||||
|
## classifies a floating point value. Returns `x`'s class as specified by
|
||||||
|
## `TFloatClass`
|
||||||
|
|
||||||
|
# implementation
|
||||||
|
|
||||||
|
include cntbits
|
||||||
|
|
||||||
|
proc nextPowerOfTwo(x: int): int =
|
||||||
|
result = x - 1
|
||||||
|
when defined(cpu64):
|
||||||
|
result = result or (result shr 32)
|
||||||
|
result = result or (result shr 16)
|
||||||
|
result = result or (result shr 8)
|
||||||
|
result = result or (result shr 4)
|
||||||
|
result = result or (result shr 2)
|
||||||
|
result = result or (result shr 1)
|
||||||
|
Inc(result)
|
||||||
|
|
||||||
|
# C procs:
|
||||||
|
proc gettime(dummy: ptr cint): cint {.
|
||||||
|
importc: "time", header: "<time.h>".}
|
||||||
|
proc srand(seed: cint) {.
|
||||||
|
importc: "srand", nodecl.}
|
||||||
|
proc rand(): cint {.importc: "rand", nodecl.}
|
||||||
|
|
||||||
|
# most C compilers have no classify:
|
||||||
|
proc classify(x: float): TFloatClass =
|
||||||
|
if x == 0.0:
|
||||||
|
if 1.0/x == 1.0/0.0:
|
||||||
|
return fcZero
|
||||||
|
else:
|
||||||
|
return fcNegZero
|
||||||
|
if x*0.5 == x:
|
||||||
|
if x > 0.0: return fcInf
|
||||||
|
else: return fcNegInf
|
||||||
|
if x != x: return fcNan
|
||||||
|
return fcNormal
|
||||||
|
# XXX: fcSubnormal is not detected!
|
||||||
|
|
||||||
|
proc randomize() = srand(gettime(nil))
|
||||||
|
proc random(max: int): int = return rand() mod max
|
||||||
|
|
||||||
|
proc isPowerOfTwo(x: int): bool = return (x and -x) == x
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
{.pop.}
|
||||||
599
lib/memman.nim
Executable file
599
lib/memman.nim
Executable file
|
|
@ -0,0 +1,599 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2008 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Memory manager. Based on:
|
||||||
|
# Two Levels Segregate Fit memory allocator (TLSF)
|
||||||
|
# Version 2.4.2
|
||||||
|
#
|
||||||
|
# Written by Miguel Masmano Tello <mimastel@doctor.upv.es>
|
||||||
|
#
|
||||||
|
# Thanks to Ismael Ripoll for his suggestions and reviews
|
||||||
|
#
|
||||||
|
# Copyright (C) 2008, 2007, 2006, 2005, 2004
|
||||||
|
#
|
||||||
|
# This code is released using a dual license strategy: GPL/LGPL
|
||||||
|
# You can choose the licence that better fits your requirements.
|
||||||
|
#
|
||||||
|
# Released under the terms of the GNU General Public License Version 2.0
|
||||||
|
# Released under the terms of the GNU Lesser General Public License Version 2.1
|
||||||
|
|
||||||
|
|
||||||
|
# Some IMPORTANT TLSF parameters
|
||||||
|
const
|
||||||
|
blockAlign = sizeof(pointer) * 2
|
||||||
|
maxFli = 30
|
||||||
|
maxLog2Sli = 5
|
||||||
|
maxSli = 1 shl maxLog2Sli
|
||||||
|
|
||||||
|
fliOffset = 6 # tlsf structure just will manage blocks bigger than 128 bytes
|
||||||
|
smallBlock = 128
|
||||||
|
realFli = MaxFli - fliOffset
|
||||||
|
|
||||||
|
type
|
||||||
|
TFreePtr = record
|
||||||
|
prev, next: PBhdr
|
||||||
|
Pbhdr = ptr Tbhdr
|
||||||
|
Tbhdr = record
|
||||||
|
prevHdr: Pbhdr # this is just valid if the first bit of size is set
|
||||||
|
size: int # the size is stored in bytes
|
||||||
|
# bit 0 indicates whether the block is used and
|
||||||
|
# bit 1 allows to know whether the previous block is free
|
||||||
|
freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the
|
||||||
|
# C version)
|
||||||
|
TAreaInfo = record # This structure is embedded at the beginning of each
|
||||||
|
# area, giving us enough information to cope with a set
|
||||||
|
# of areas
|
||||||
|
theEnd: Pbhdr
|
||||||
|
next: PAreaInfo
|
||||||
|
PAreaInfo = ptr TAreaInfo
|
||||||
|
|
||||||
|
TLSF = record
|
||||||
|
tlsf_signature: int32 # the TLSF's structure signature
|
||||||
|
usedSize, maxSize: int
|
||||||
|
areaHead: PAreaInfo # A linked list holding all the existing areas
|
||||||
|
|
||||||
|
flBitmap: int32 # the first-level bitmap
|
||||||
|
# This array should have a size of REAL_FLI bits
|
||||||
|
slBitmap: array[0..realFli, int32] # the second-level bitmap
|
||||||
|
matrix: array [0..realFli, array[0..maxSli, PBhdr]]
|
||||||
|
|
||||||
|
const
|
||||||
|
minBlockSize = sizeof(TFreePtr)
|
||||||
|
bhdrOverhead = sizeof(Tbhdr) - minBlockSize
|
||||||
|
tlsfSignature = 0x2A59FA59
|
||||||
|
ptrMask = sizeof(pointer) - 1
|
||||||
|
blockSize = 0xFFFFFFFF - ptrMask
|
||||||
|
memAlign = blockAlign - 1
|
||||||
|
blockState = 0x1
|
||||||
|
prevState = 0x2
|
||||||
|
|
||||||
|
freeBlock = 0x1 # bit 0 of the block size
|
||||||
|
usedBlock = 0x0
|
||||||
|
|
||||||
|
prevFree = 0x2 # bit 1 of the block size
|
||||||
|
prevUsed = 0x0
|
||||||
|
|
||||||
|
defaultAreaSize = 64*1024 # 1024*10
|
||||||
|
pageSize = if defined(cpu32): 4096 else: 4096*2
|
||||||
|
|
||||||
|
|
||||||
|
proc getNextBlock(adr: pointer, r: int): PBhdr {.inline.} =
|
||||||
|
return cast[PBhdr](cast[TAddress](adr) +% r)
|
||||||
|
|
||||||
|
proc roundupSize(r: int): int = return (r +% memAlign) and not memAlign
|
||||||
|
proc rounddownSize(r: int): int = return r and not memAlign
|
||||||
|
proc roundup(x, v: int): int = return (((not x)+%1) and (v-%1)) +% x
|
||||||
|
|
||||||
|
proc addSize(s: PTLSF, b: Pbhdr) =
|
||||||
|
inc(s.usedSize, (b.size and blockSize) + bhdrOverhead)
|
||||||
|
s.maxSize = max(s.maxSize, s.usedSize)
|
||||||
|
|
||||||
|
proc removeSize(s: PTLSF, b: Pbhdr) =
|
||||||
|
dec(s.usedSize, (b.size and blockSize) + bhdrOverhead)
|
||||||
|
|
||||||
|
# ------------ platform specific code -----------------------------------------
|
||||||
|
|
||||||
|
when defined(posix):
|
||||||
|
const # XXX: make these variables for portability?
|
||||||
|
PROT_READ = 1 # page can be read
|
||||||
|
PROT_WRITE = 2 # page can be written
|
||||||
|
PROT_EXEC = 4 # page can be executed
|
||||||
|
PROT_NONE = 0 # page can not be accessed
|
||||||
|
|
||||||
|
MAP_SHARED = 1 # Share changes
|
||||||
|
MAP_PRIVATE = 2 # Changes are private
|
||||||
|
MAP_TYPE = 0xf # Mask for type of mapping
|
||||||
|
MAP_FIXED = 0x10 # Interpret addr exactly
|
||||||
|
MAP_ANONYMOUS = 0x20 # don't use a file
|
||||||
|
|
||||||
|
MAP_GROWSDOWN = 0x100 # stack-like segment
|
||||||
|
MAP_DENYWRITE = 0x800 # ETXTBSY
|
||||||
|
MAP_EXECUTABLE = 0x1000 # mark it as an executable
|
||||||
|
MAP_LOCKED = 0x2000 # pages are locked
|
||||||
|
MAP_NORESERVE = 0x4000 # don't check for reservations
|
||||||
|
|
||||||
|
proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
|
||||||
|
off: int): pointer {.header: "<sys/mman.h>".}
|
||||||
|
|
||||||
|
proc getNewArea(size: var int): pointer {.inline.} =
|
||||||
|
size = roundup(size, PageSize)
|
||||||
|
result = mmap(0, size, PROT_READ or PROT_WRITE,
|
||||||
|
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
|
||||||
|
if result == nil or result == cast[pointer](-1):
|
||||||
|
raiseOutOfMem()
|
||||||
|
|
||||||
|
elif defined(windows):
|
||||||
|
const
|
||||||
|
MEM_RESERVE = 0x2000
|
||||||
|
MEM_COMMIT = 0x1000
|
||||||
|
MEM_TOP_DOWN = 0x100000
|
||||||
|
PAGE_READWRITE = 0x04
|
||||||
|
|
||||||
|
proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
|
||||||
|
flProtect: int32): pointer {.
|
||||||
|
header: "<windows.h>", stdcall.}
|
||||||
|
|
||||||
|
proc getNewArea(size: var int): pointer {.inline.} =
|
||||||
|
size = roundup(size, PageSize)
|
||||||
|
result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT or MEM_TOP_DOWN,
|
||||||
|
PAGE_READWRITE)
|
||||||
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# generic implementation relying on malloc:
|
||||||
|
proc malloc(size: int): pointer {.nodecl, importc.}
|
||||||
|
|
||||||
|
proc getNewArea(size: var int): pointer {.inline.} =
|
||||||
|
size = roundup(size, PageSize)
|
||||||
|
result = malloc(size)
|
||||||
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# helpers
|
||||||
|
|
||||||
|
const
|
||||||
|
table: array[0..255, int8] = [
|
||||||
|
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||||
|
6, 6, 6, 6, 6, 6, 6, 6,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7
|
||||||
|
]
|
||||||
|
|
||||||
|
proc ls_bit(i: int32): int {.inline.} =
|
||||||
|
var
|
||||||
|
a: int = 0
|
||||||
|
x: int = i and -i
|
||||||
|
if x <=% 0xffff:
|
||||||
|
if x <=% ff: a = 0
|
||||||
|
else: a = 8
|
||||||
|
elif x <=% 0xffffff: a = 16
|
||||||
|
else: a = 24
|
||||||
|
return table[x shr a] + a
|
||||||
|
|
||||||
|
proc ms_bit(i: int): int {.inline.} =
|
||||||
|
var
|
||||||
|
a = if i <=% 0xffff: (if i <=% 0xff: 0 else: 8) elif
|
||||||
|
i <=% 0xffffff: 16 else: 24
|
||||||
|
return table[i shr a] + a
|
||||||
|
|
||||||
|
proc set_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
|
||||||
|
adr[nr shr 5] = adr[nr shr 5] or (1 shl (nr and 0x1f))
|
||||||
|
|
||||||
|
proc clear_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
|
||||||
|
adr[nr shr 5] = adr[nr shr 5] and not (1 shl (nr and 0x1f))
|
||||||
|
|
||||||
|
proc mappingSearch(r, fl, sl: var int) {.inline.} =
|
||||||
|
if r < smallBlock:
|
||||||
|
fl = 0
|
||||||
|
sl = r div (smallBlock div maxSli)
|
||||||
|
else:
|
||||||
|
var t = (1 shl (ms_bit(r) - maxLog2Sli)) - 1
|
||||||
|
r = r + t
|
||||||
|
fl = ms_bit(r)
|
||||||
|
sl = (r shl (fl - maxLog2Sli)) - maxSli
|
||||||
|
fl = fl - fliOffset
|
||||||
|
r = r and not t
|
||||||
|
|
||||||
|
proc mappingInsert(r: int, fl, sl: var int) {.inline.} =
|
||||||
|
if r < smallBlock:
|
||||||
|
fl = 0
|
||||||
|
sl = r div (smallBlock div maxSli)
|
||||||
|
else:
|
||||||
|
fl = ms_bit(r)
|
||||||
|
sl = (r shr (fl - maxLog2Sli)) - maxSli
|
||||||
|
fl = fl - fliOffset
|
||||||
|
|
||||||
|
proc findSuitableBlock(t: var TLSF, fl, sl: var int): Pbhdr =
|
||||||
|
var tmp = t.slBitmap[fl] and ((not 0) shl sl)
|
||||||
|
if tmp != 0:
|
||||||
|
sl = ls_bit(tmp)
|
||||||
|
result = t.matrix[fl][sl]
|
||||||
|
else:
|
||||||
|
fl = ls_bit(t.flBitmap and (not 0 shl (fl + 1)))
|
||||||
|
if fl > 0: # likely
|
||||||
|
sl = ls_bit(t.slBitmap[fl])
|
||||||
|
result = t.matrix[fl][sl]
|
||||||
|
|
||||||
|
proc extractBlockHdr(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
|
||||||
|
t.matrix[fl][sl] = b.freePtr.next
|
||||||
|
if t.matrix[fl][sl] != 0:
|
||||||
|
t.matrix[fl][sl].freePtr.prev = nil
|
||||||
|
else:
|
||||||
|
clear_bit(sl, t.slBitmap[fl])
|
||||||
|
if t.slBitmap[fl] == 0:
|
||||||
|
clear_bit(fl, t.flBitmap)
|
||||||
|
b.freePtr.prev = nil
|
||||||
|
b.freePtr.next = nil
|
||||||
|
|
||||||
|
proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
|
||||||
|
if b.freePtr.next != nil:
|
||||||
|
b.freePtr.next.freePtr.prev = b.freePtr.prev
|
||||||
|
if b.freePtr.prev != nil:
|
||||||
|
b.freePtr.prev.freePtr.next = b.freePtr.next
|
||||||
|
if t.matrix[fl][sl] == b:
|
||||||
|
t.matrix[fl][sl] = b.freePtr.next
|
||||||
|
if t.matrix[fl][sl] == nil:
|
||||||
|
clear_bit(sl, t.slBitmap[fl])
|
||||||
|
if t.slBitmap[fl] == 0:
|
||||||
|
clear_bit(fl, t.flBitmap)
|
||||||
|
b.freePtr.prev = nil
|
||||||
|
b.freePtr.next = nil
|
||||||
|
|
||||||
|
proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
|
||||||
|
b.freePtr.prev = nil
|
||||||
|
b.freePtr.next = t.matrix[fl][sl]
|
||||||
|
if t.matrix[fl][sl] != 0:
|
||||||
|
t.matrix[fl][sl].freePtr.prev = b
|
||||||
|
t.matrix[fl][sl] = b
|
||||||
|
set_bit(sl, t.slBitmap[fl])
|
||||||
|
set_bit(fl, t.flBitmap)
|
||||||
|
|
||||||
|
proc getBuffer(b: Pbhdr): pointer {.inline.} =
|
||||||
|
result = cast[pointer](addr(b.freePtr))
|
||||||
|
|
||||||
|
proc processArea(area: pointer, size: int): Pbhdr =
|
||||||
|
var
|
||||||
|
b, lb, ib: Pbhdr
|
||||||
|
ai: PAreaInfo
|
||||||
|
ib = cast[Pbhdr](area)
|
||||||
|
if sizeof(TAreaInfo) < minBlockSize:
|
||||||
|
ib.size = minBlockSize or usedBlock or prevUsed
|
||||||
|
else
|
||||||
|
ib.size = roundupSize(sizeof(TAreaInfo)) or usedBlock or prevUsed
|
||||||
|
b = getNextBlock(getBuffer(ib), ib.size and blockSize)
|
||||||
|
b.size = rounddownSize(size - 3 * bhdrOverhead - (ib.size and blockSize)) or
|
||||||
|
usedBlock or prevUsed
|
||||||
|
b.freePtr.prev = nil
|
||||||
|
b.freePtr.next = nil
|
||||||
|
lb = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
lb.prevHdr = b
|
||||||
|
lb.size = 0 or usedBlock or prevFree
|
||||||
|
ai = cast[PAreaInfo](getBuffer(ib))
|
||||||
|
ai.next = nil
|
||||||
|
ai.theEnd = lb
|
||||||
|
return ib
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Begin of the allocator code
|
||||||
|
|
||||||
|
var
|
||||||
|
mp: pointer # default memory pool.
|
||||||
|
|
||||||
|
proc initMemoryPool(memPoolSize: int, memPool: pointer): int =
|
||||||
|
var
|
||||||
|
t: PLSF
|
||||||
|
b, ib: Pbhdr
|
||||||
|
|
||||||
|
if memPool == nil or memPoolSize < sizeof(TLSF) + bhdrOverhead * 8:
|
||||||
|
writeToStdErr("initMemoryPool(): memory_pool invalid\n")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
if (memPool and ptrMask) != 0:
|
||||||
|
writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n")
|
||||||
|
return -1
|
||||||
|
t = cast[PLSF](memPool)
|
||||||
|
# Check if already initialised
|
||||||
|
if t.signature == tlsfSignature:
|
||||||
|
mp = memPool
|
||||||
|
b = getNextBlock(mp, roundupSize(sizeof(TLSF)))
|
||||||
|
return b.size and blockSize
|
||||||
|
mp = memPool
|
||||||
|
zeroMem(memPool, sizeof(TLSF))
|
||||||
|
|
||||||
|
t.signature = tlsfSignature
|
||||||
|
ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))),
|
||||||
|
rounddownSize(memPoolSize - sizeof(TLSF)))
|
||||||
|
b = getNextBlock(getBuffer(ib), ib.size and blockSize)
|
||||||
|
freeEx(getBuffer(b), t)
|
||||||
|
t.areaHead = cast[PAreaInfo](getBuffer(ib))
|
||||||
|
|
||||||
|
t.used_size = memPoolSize - (b.size and blockSize)
|
||||||
|
t.max_size = t.used_size
|
||||||
|
return b.size and blockSize
|
||||||
|
|
||||||
|
|
||||||
|
proc addNewArea(area: pointer, areaSize: int, t: var TLSF): int =
|
||||||
|
var
|
||||||
|
p, ptrPrev, ai: PAreaInfo
|
||||||
|
ib0, b0, lb0, ib1, b1, lb1, nextB: Pbhdr
|
||||||
|
|
||||||
|
zeroMem(area, areaSize)
|
||||||
|
p = t.areaHead
|
||||||
|
ptrPrev = 0
|
||||||
|
|
||||||
|
ib0 = processArea(area, areaSize)
|
||||||
|
b0 = getNextBlock(getBuffer(ib0), ib0.size and blockSize)
|
||||||
|
lb0 = getNextBlock(getBuffer(b0), b0.size and blockSize)
|
||||||
|
|
||||||
|
# Before inserting the new area, we have to merge this area with the
|
||||||
|
# already existing ones
|
||||||
|
while p != nil:
|
||||||
|
ib1 = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
|
||||||
|
b1 = getNextBlock(getBuffer(ib1), ib1.size and blockSize)
|
||||||
|
lb1 = p.theEnd
|
||||||
|
|
||||||
|
# Merging the new area with the next physically contigous one
|
||||||
|
if cast[TAddress](ib1) == cast[TAddress](lb0) +% bhdrOverhead:
|
||||||
|
if t.areaHead == p:
|
||||||
|
t.areaHead = p.next
|
||||||
|
p = p.next
|
||||||
|
else:
|
||||||
|
ptrPrev.next = p.next
|
||||||
|
p = p.next
|
||||||
|
b0.size = rounddownSize((b0.size and blockSize) +
|
||||||
|
(ib1.size and blockSize) + 2 * bhdrOverhead) or
|
||||||
|
usedBlock or prevUsed
|
||||||
|
b1.prevHdr = b0
|
||||||
|
lb0 = lb1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Merging the new area with the previous physically contigous one
|
||||||
|
if getBuffer(lb1) == pointer(ib0):
|
||||||
|
if t.areaHead == p:
|
||||||
|
t.areaHead = p.next
|
||||||
|
p = p.next
|
||||||
|
else:
|
||||||
|
ptrPrev.next = p.next
|
||||||
|
p = p.next
|
||||||
|
lb1->size = rounddownSize((b0.size and blockSize) +
|
||||||
|
(ib0.size and blockSize) + 2 * bhdrOverhead) or
|
||||||
|
usedBlock or (lb1.size and prevState)
|
||||||
|
nextB = getNextBlock(getBuffer(lb1), lb1.size and blockSize)
|
||||||
|
nextB.prevHdr = lb1
|
||||||
|
b0 = lb1
|
||||||
|
ib0 = ib1
|
||||||
|
continue
|
||||||
|
ptrPrev = p
|
||||||
|
p = p.next
|
||||||
|
|
||||||
|
# Inserting the area in the list of linked areas
|
||||||
|
ai = cast[PAreaInfo](getBuffer(ib0))
|
||||||
|
ai.next = t.areaHead
|
||||||
|
ai.theEnd = lb0
|
||||||
|
t.areaHead = ai
|
||||||
|
freeEx(getBuffer(b0), memPool)
|
||||||
|
return (b0.size and blockSize)
|
||||||
|
|
||||||
|
proc mallocEx(asize: int, t: var TLSF): pointer =
|
||||||
|
var
|
||||||
|
b, b2, nextB: Pbhdr
|
||||||
|
fl, sl, tmpSize, size: int
|
||||||
|
|
||||||
|
size = if asize < minBlockSize: minBlockSize else: roundupSize(asize)
|
||||||
|
|
||||||
|
# Rounding up the requested size and calculating fl and sl
|
||||||
|
mappingSearch(size, fl, sl)
|
||||||
|
|
||||||
|
# Searching a free block, recall that this function changes the values
|
||||||
|
# of fl and sl, so they are not longer valid when the function fails
|
||||||
|
b = findSuitableBlock(tlsf, fl, sl)
|
||||||
|
if b == nil:
|
||||||
|
# Growing the pool size when needed
|
||||||
|
# size plus enough room for the required headers:
|
||||||
|
var areaSize = max(size + bhdrOverhead * 8, defaultAreaSize)
|
||||||
|
var area = getNewArea(areaSize)
|
||||||
|
addNewArea(area, areaSize, t)
|
||||||
|
# Rounding up the requested size and calculating fl and sl
|
||||||
|
mappingSearch(size, fl, sl)
|
||||||
|
# Searching a free block
|
||||||
|
b = findSuitableBlock(t, fl, sl)
|
||||||
|
if b == nil:
|
||||||
|
raiseOutOfMem()
|
||||||
|
|
||||||
|
extractBlockHdr(b, t, fl, sl)
|
||||||
|
|
||||||
|
#-- found:
|
||||||
|
nextB = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
# Should the block be split?
|
||||||
|
tmpSize = (b.size and blockSize) - size
|
||||||
|
if tmpSize >= sizeof(Tbhdr):
|
||||||
|
dec(tmpSize, bhdrOverhead)
|
||||||
|
b2 = getNextBlock(getBuffer(b), size)
|
||||||
|
b2.size = tmpSize or freeBlock or prevUsed
|
||||||
|
nextB.prevHdr = b2
|
||||||
|
mappingInsert(tmpSize, fl, sl)
|
||||||
|
insertBlock(b2, t, fl, sl)
|
||||||
|
|
||||||
|
b.size = size or (b.size and prevState)
|
||||||
|
else:
|
||||||
|
nextB.size = nextB.size and not prevFree
|
||||||
|
b.size = b.size and not freeBlock # Now it's used
|
||||||
|
|
||||||
|
addSize(t, b)
|
||||||
|
return getBuffer(b)
|
||||||
|
|
||||||
|
|
||||||
|
proc freeEx(p: pointer, t: var TLSF) =
|
||||||
|
var
|
||||||
|
fl = 0
|
||||||
|
sl = 0
|
||||||
|
b, tmpB: Pbhdr
|
||||||
|
|
||||||
|
assert(p != nil)
|
||||||
|
b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
|
||||||
|
b.size = b.size or freeBlock
|
||||||
|
|
||||||
|
removeSize(t, b)
|
||||||
|
b.freePtr.prev = nil
|
||||||
|
b.freePtr.next = nil
|
||||||
|
tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
if tmpB.size and freeBlock != 0:
|
||||||
|
mappingInsert(tmpB.size and blockSize, fl, sl)
|
||||||
|
extractBlock(tmpB, t, fl, sl)
|
||||||
|
inc(b.size, (tmpB.size and blockSize) + bhdrOverhead)
|
||||||
|
if (b.size and prevFree) != 0:
|
||||||
|
tmpB = b.prevHdr
|
||||||
|
mappingInsert(tmpB.size and blockSize, fl, sl)
|
||||||
|
extractBlock(tmpB, t, fl, sl)
|
||||||
|
inc(tmpB.size, (b.size and blockSize) + bhdrOverhead)
|
||||||
|
b = tmpB
|
||||||
|
mappingInsert(b.size and blockSize, fl, sl)
|
||||||
|
insertBlock(b, t, fl, sl)
|
||||||
|
|
||||||
|
tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
tmpB.size = tmpB.size or prevFree
|
||||||
|
tmpB.prevHdr = b
|
||||||
|
|
||||||
|
proc reallocEx(p: pointer, newSize: int, t: var TLSF): pointer =
|
||||||
|
var
|
||||||
|
cpsize, fl, sl, tmpSize: int
|
||||||
|
b, tmpB, nextB: Pbhdr
|
||||||
|
|
||||||
|
assert(p != nil)
|
||||||
|
assert(newSize > 0)
|
||||||
|
|
||||||
|
b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
|
||||||
|
nextB = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
newSize = if newSize < minBlockSize: minBlockSize else: roundupSize(newSize)
|
||||||
|
tmpSize = b.size and blockSize
|
||||||
|
if newSize <= tmpSize:
|
||||||
|
removeSize(t, b)
|
||||||
|
if (nextB.size and freeBlock) != 0:
|
||||||
|
mappingInsert(nextB.size and blockSize, fl, sl)
|
||||||
|
extractBlock(nextB, t, fl, sl)
|
||||||
|
inc(tmpSize, (nextB.size and blockSize) + bhdrOverhead)
|
||||||
|
nextB = getNextBlock(getBuffer(nextB), nextB.size and blockSize)
|
||||||
|
# We always reenter this free block because tmpSize will
|
||||||
|
# be greater then sizeof(Tbhdr)
|
||||||
|
dec(tmpSize, newSize)
|
||||||
|
if tmpSize >= sizeof(Tbhdr):
|
||||||
|
dec(tmpSize, bhdrOverhead)
|
||||||
|
tmpB = getNextBlock(getBuffer(b), newSize)
|
||||||
|
tmpB.size = tmpSize or freeBlock or prevUsed
|
||||||
|
nextB.prevHdr = tmpB
|
||||||
|
nextB.size = nextB.size or prevFree
|
||||||
|
mappingInsert(tmpSize, fl, sl)
|
||||||
|
insertBlock(tmpB, t, fl, sl)
|
||||||
|
b.size = newSize or (b.size and prevState)
|
||||||
|
addSize(t, b)
|
||||||
|
return getBuffer(b)
|
||||||
|
|
||||||
|
if (nextB.size and freeBlock) != 0:
|
||||||
|
if newSize <= tmpSize + (nextB.size and blockSize):
|
||||||
|
removeSize(t, b)
|
||||||
|
mappingInsert(nextB.size and blockSize, fl, sl)
|
||||||
|
extractBlock(nextB, t, fl, sl)
|
||||||
|
inc(b.size, (nextB.size and blockSize) + bhdrOverhead)
|
||||||
|
nextB = getNextBlock(getBuffer(b), b.size and blockSize)
|
||||||
|
nextB.prevHdr = b
|
||||||
|
nextB.size = nextB.size and not prevFree
|
||||||
|
tmpSize = (b.size and blockSize) - newSize
|
||||||
|
if tmpSize >= sizeof(Tbhdr):
|
||||||
|
dec(tmpSize, bhdrOverhead)
|
||||||
|
tmpB = getNextBlock(getBuffer(b), newSize)
|
||||||
|
tmpB.size = tmpSize or freeBlock or prevUsed
|
||||||
|
nextB.prevHdr = tmpB
|
||||||
|
nextB.size = nextB.size or prevFree
|
||||||
|
mappingInsert(tmpSize, fl, sl)
|
||||||
|
insertBlock(tmpB, t, fl, sl)
|
||||||
|
b.size = newSize or (b.size and prevState)
|
||||||
|
addSize(t, b)
|
||||||
|
return getBuffer(b)
|
||||||
|
|
||||||
|
var ptrAux = mallocEx(newSize, t)
|
||||||
|
cpsize = if (b.size and blockSize) > newSize: newSize else:
|
||||||
|
(b.size and blockSize)
|
||||||
|
copyMem(ptrAux, p, cpsize)
|
||||||
|
freeEx(p, memPool)
|
||||||
|
return ptrAux
|
||||||
|
|
||||||
|
|
||||||
|
proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer =
|
||||||
|
if p == nil:
|
||||||
|
if newSize > 0:
|
||||||
|
result = mallocEx(newSize, t)
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
elif newSize <= 0:
|
||||||
|
freeEx(p, t)
|
||||||
|
result = nil
|
||||||
|
else:
|
||||||
|
result = reallocEx(p, newSize, t)
|
||||||
|
|
||||||
|
|
||||||
|
void *tlsf_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ret
|
||||||
|
|
||||||
|
#if USE_MMAP || USE_SBRK
|
||||||
|
if (!mp) {
|
||||||
|
size_t areaSize
|
||||||
|
void *area
|
||||||
|
|
||||||
|
areaSize = sizeof(tlsf_t) + BHDR_OVERHEAD * 8 # Just a safety constant
|
||||||
|
areaSize = (areaSize > DEFAULT_areaSize) ? areaSize : DEFAULT_areaSize
|
||||||
|
area = get_new_area(&areaSize)
|
||||||
|
if (area == ((void *) ~0))
|
||||||
|
return NULL # Not enough system memory
|
||||||
|
initMemoryPool(areaSize, area)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
|
||||||
|
ret = malloc_ex(size, mp)
|
||||||
|
|
||||||
|
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
void tlsf_free(void *p)
|
||||||
|
{
|
||||||
|
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
free_ex(p, mp)
|
||||||
|
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tlsf_realloc(void *p, size_t size)
|
||||||
|
{
|
||||||
|
void *ret
|
||||||
|
#if USE_MMAP || USE_SBRK
|
||||||
|
if (!mp) {
|
||||||
|
return tlsf_malloc(size)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
ret = realloc_ex(p, size, mp)
|
||||||
|
TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
403
lib/nimbase.h
Executable file
403
lib/nimbase.h
Executable file
|
|
@ -0,0 +1,403 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Nimrod's Runtime Library
|
||||||
|
(c) Copyright 2006 Andreas Rumpf
|
||||||
|
|
||||||
|
See the file "copying.txt", included in this
|
||||||
|
distribution, for details about the copyright.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NIMBASE_H
|
||||||
|
#define NIMBASE_H
|
||||||
|
|
||||||
|
/* calling convention mess ----------------------------------------------- */
|
||||||
|
#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__)
|
||||||
|
/* these should support C99's inline */
|
||||||
|
/* the test for __POCC__ has to come before the test for _MSC_VER,
|
||||||
|
because PellesC defines _MSC_VER too. This is brain-dead. */
|
||||||
|
# define N_INLINE(rettype, name) inline rettype name
|
||||||
|
#elif defined(__BORLANDC__) || defined(_MSC_VER)
|
||||||
|
/* Borland's compiler is really STRANGE here; note that the __fastcall
|
||||||
|
keyword cannot be before the return type, but __inline cannot be after
|
||||||
|
the return type, so we do not handle this mess in the code generator
|
||||||
|
but rather here. */
|
||||||
|
# define N_INLINE(rettype, name) __inline rettype name
|
||||||
|
#elif defined(__DMC__)
|
||||||
|
# define N_INLINE(rettype, name) inline rettype name
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
# define N_INLINE(rettype, name) __inline rettype name
|
||||||
|
#else /* others are less picky: */
|
||||||
|
# define N_INLINE(rettype, name) rettype __inline name
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define HAVE_LRINT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* --------------- how int64 constants should be declared: ----------- */
|
||||||
|
#if defined(__GNUC__) || defined(__LCC__) || \
|
||||||
|
defined(__POCC__) || defined(__DMC__)
|
||||||
|
# define IL64(x) x##LL
|
||||||
|
#else /* works only without LL */
|
||||||
|
# define IL64(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) /* only Windows has this mess... */
|
||||||
|
# define N_CDECL(rettype, name) rettype __cdecl name
|
||||||
|
# define N_STDCALL(rettype, name) rettype __stdcall name
|
||||||
|
# define N_SYSCALL(rettype, name) rettype __syscall name
|
||||||
|
# define N_FASTCALL(rettype, name) rettype __fastcall name
|
||||||
|
# define N_SAFECALL(rettype, name) rettype __safecall name
|
||||||
|
/* function pointers with calling convention: */
|
||||||
|
# define N_CDECL_PTR(rettype, name) rettype (__cdecl *name)
|
||||||
|
# define N_STDCALL_PTR(rettype, name) rettype (__stdcall *name)
|
||||||
|
# define N_SYSCALL_PTR(rettype, name) rettype (__syscall *name)
|
||||||
|
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
||||||
|
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
||||||
|
|
||||||
|
# define N_LIB_EXPORT __declspec(dllexport)
|
||||||
|
# define N_LIB_IMPORT __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
# define N_CDECL(rettype, name) rettype name
|
||||||
|
# define N_STDCALL(rettype, name) rettype name
|
||||||
|
# define N_SYSCALL(rettype, name) rettype name
|
||||||
|
# define N_FASTCALL(rettype, name) rettype name
|
||||||
|
# define N_SAFECALL(rettype, name) rettype name
|
||||||
|
/* function pointers with calling convention: */
|
||||||
|
# define N_CDECL_PTR(rettype, name) rettype (*name)
|
||||||
|
# define N_STDCALL_PTR(rettype, name) rettype (*name)
|
||||||
|
# define N_SYSCALL_PTR(rettype, name) rettype (*name)
|
||||||
|
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
||||||
|
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
|
# define N_LIB_EXPORT
|
||||||
|
# define N_LIB_IMPORT extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define N_NOCONV(rettype, name) rettype name
|
||||||
|
/* specify no calling convention */
|
||||||
|
#define N_NOCONV_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
|
#define N_CLOSURE(rettype, name) rettype name
|
||||||
|
/* specify no calling convention */
|
||||||
|
#define N_CLOSURE_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__BORLANDC__) || defined(__WATCOMC__) || \
|
||||||
|
defined(__POCC__) || defined(_MSC_VER)
|
||||||
|
/* these compilers have a fastcall so use it: */
|
||||||
|
# define N_NIMCALL(rettype, name) rettype __fastcall name
|
||||||
|
# define N_NIMCALL_PTR(rettype, name) rettype (__fastcall *name)
|
||||||
|
#else
|
||||||
|
# define N_NIMCALL(rettype, name) rettype name /* no modifier */
|
||||||
|
# define N_NIMCALL_PTR(rettype, name) rettype (*name)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* from float_cast.h: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
|
||||||
|
**
|
||||||
|
** Permission to use, copy, modify, distribute, and sell this file for any
|
||||||
|
** purpose is hereby granted without fee, provided that the above copyright
|
||||||
|
** and this permission notice appear in all copies. No representations are
|
||||||
|
** made about the suitability of this software for any purpose. It is
|
||||||
|
** provided "as is" without express or implied warranty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Version 1.1 */
|
||||||
|
|
||||||
|
|
||||||
|
/*============================================================================
|
||||||
|
** On Intel Pentium processors (especially PIII and probably P4), converting
|
||||||
|
** from float to int is very slow. To meet the C specs, the code produced by
|
||||||
|
** most C compilers targeting Pentium needs to change the FPU rounding mode
|
||||||
|
** before the float to int conversion is performed.
|
||||||
|
**
|
||||||
|
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
|
||||||
|
** is this flushing of the pipeline which is so slow.
|
||||||
|
**
|
||||||
|
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
|
||||||
|
** llrint and llrintf which fix this problem as a side effect.
|
||||||
|
**
|
||||||
|
** On Unix-like systems, the configure process should have detected the
|
||||||
|
** presence of these functions. If they weren't found we have to replace them
|
||||||
|
** here with a standard C cast.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The C99 prototypes for lrint and lrintf are as follows:
|
||||||
|
**
|
||||||
|
** long int lrintf (float x);
|
||||||
|
** long int lrint (double x);
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__LCC__) || defined(__POCC__) \
|
||||||
|
|| (defined(__GNUC__) && defined(WIN32))
|
||||||
|
/* Linux' GCC does not seem to have these. Why? */
|
||||||
|
# define HAVE_LRINT
|
||||||
|
# define HAVE_LRINTF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LRINT) && defined(HAVE_LRINTF)
|
||||||
|
|
||||||
|
/* These defines enable functionality introduced with the 1999 ISO C
|
||||||
|
** standard. They must be defined before the inclusion of math.h to
|
||||||
|
** engage them. If optimisation is enabled, these functions will be
|
||||||
|
** inlined. With optimisation switched off, you have to link in the
|
||||||
|
** maths library using -lm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# define _ISOC9X_SOURCE 1
|
||||||
|
# define _ISOC99_SOURCE 1
|
||||||
|
# define __USE_ISOC9X 1
|
||||||
|
# define __USE_ISOC99 1
|
||||||
|
# include <math.h>
|
||||||
|
|
||||||
|
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
|
||||||
|
&& !defined(__BORLANDC__)
|
||||||
|
|
||||||
|
# include <math.h>
|
||||||
|
|
||||||
|
/* Win32 doesn't seem to have these functions.
|
||||||
|
** Therefore implement inline versions of these functions here.
|
||||||
|
*/
|
||||||
|
static N_INLINE(long int, lrint)(double flt) {
|
||||||
|
long int intgr;
|
||||||
|
_asm {
|
||||||
|
fld flt
|
||||||
|
fistp intgr
|
||||||
|
};
|
||||||
|
return intgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static N_INLINE(long int, lrintf)(float flt) {
|
||||||
|
long int intgr;
|
||||||
|
_asm {
|
||||||
|
fld flt
|
||||||
|
fistp intgr
|
||||||
|
};
|
||||||
|
return intgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# include <math.h>
|
||||||
|
|
||||||
|
# ifndef lrint
|
||||||
|
# define lrint(dbl) ((long int)(dbl))
|
||||||
|
# endif
|
||||||
|
# ifndef lrintf
|
||||||
|
# define lrintf(flt) ((long int)(flt))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif /* defined(HAVE_LRINT) && defined(HAVE_LRINTF) */
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/* compiler symbols:
|
||||||
|
__BORLANDC__
|
||||||
|
_MSC_VER
|
||||||
|
__WATCOMC__
|
||||||
|
__LCC__
|
||||||
|
__GNUC__
|
||||||
|
__DMC__
|
||||||
|
__POCC__
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* C99 compiler? */
|
||||||
|
#if (defined(__STD_VERSION__) && (__STD_VERSION__ >= 199901))
|
||||||
|
# define HAVE_STDINT_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__LCC__) || defined(__GNUC__) || defined(__DMC__) \
|
||||||
|
|| defined(__POCC__)
|
||||||
|
# define HAVE_STDINT_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* bool types (C++ has it): */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
# ifndef NIM_TRUE
|
||||||
|
# define NIM_TRUE true
|
||||||
|
# endif
|
||||||
|
# ifndef NIM_FALSE
|
||||||
|
# define NIM_FALSE false
|
||||||
|
# endif
|
||||||
|
# define NIM_BOOL bool
|
||||||
|
#else
|
||||||
|
# ifdef bool
|
||||||
|
# define NIM_BOOL bool
|
||||||
|
# else
|
||||||
|
typedef unsigned char NIM_BOOL;
|
||||||
|
# endif
|
||||||
|
# ifndef NIM_TRUE
|
||||||
|
# define NIM_TRUE ((NIM_BOOL) 1)
|
||||||
|
# endif
|
||||||
|
# ifndef NIM_FALSE
|
||||||
|
# define NIM_FALSE ((NIM_BOOL) 0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so
|
||||||
|
the generated code does not rely on it anymore */
|
||||||
|
|
||||||
|
#if defined(HAVE_STDINT_H)
|
||||||
|
# include <stdint.h>
|
||||||
|
typedef int8_t NS8;
|
||||||
|
typedef int16_t NS16;
|
||||||
|
typedef int32_t NS32;
|
||||||
|
typedef int64_t NS64;
|
||||||
|
typedef uint64_t NU64;
|
||||||
|
typedef uint8_t NU8;
|
||||||
|
typedef uint16_t NU16;
|
||||||
|
typedef uint32_t NU32;
|
||||||
|
#elif defined(__BORLANDC__) || defined(__DMC__) \
|
||||||
|
|| defined(__WATCOMC__) || defined(_MSC_VER)
|
||||||
|
typedef signed char NS8;
|
||||||
|
typedef signed short int NS16;
|
||||||
|
typedef signed int NS32;
|
||||||
|
/* XXX: Float128? */
|
||||||
|
typedef unsigned char NU8;
|
||||||
|
typedef unsigned short int NU16;
|
||||||
|
typedef unsigned __int64 NU64;
|
||||||
|
typedef __int64 NS64;
|
||||||
|
typedef unsigned int NU32;
|
||||||
|
#else
|
||||||
|
typedef signed char NS8;
|
||||||
|
typedef signed short int NS16;
|
||||||
|
typedef signed int NS32;
|
||||||
|
/* XXX: Float128? */
|
||||||
|
typedef unsigned char NU8;
|
||||||
|
typedef unsigned short int NU16;
|
||||||
|
typedef unsigned long long int NU64;
|
||||||
|
typedef long long int NS64;
|
||||||
|
typedef unsigned int NU32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (defined(AMD64) || defined(_M_AMD64))
|
||||||
|
/* Microsoft C is brain-dead in this case; long is still not an int64 */
|
||||||
|
typedef unsigned long long int NU;
|
||||||
|
typedef signed long long int NS;
|
||||||
|
#else
|
||||||
|
typedef unsigned long int NU; /* note: int would be wrong for AMD64 */
|
||||||
|
typedef signed long int NS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef float NF32;
|
||||||
|
typedef double NF64;
|
||||||
|
typedef double NF;
|
||||||
|
|
||||||
|
typedef char NIM_CHAR;
|
||||||
|
typedef char* NCSTRING;
|
||||||
|
|
||||||
|
#ifdef NIM_BIG_ENDIAN
|
||||||
|
# define NIM_IMAN 1
|
||||||
|
#else
|
||||||
|
# define NIM_IMAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static N_INLINE(NS32, float64ToInt32)(double val) {
|
||||||
|
val = val + 68719476736.0*1.5;
|
||||||
|
/* 2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor */
|
||||||
|
return ((NS32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */
|
||||||
|
}
|
||||||
|
|
||||||
|
static N_INLINE(NS32, float32ToInt32)(float val) {
|
||||||
|
return float64ToInt32((double)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define zeroMem(a, size) memset(a, 0, size)
|
||||||
|
#define equalMem(a, b, size) (memcmp(a, b, size) == 0)
|
||||||
|
|
||||||
|
#define STRING_LITERAL(name, str, length) \
|
||||||
|
static const struct { \
|
||||||
|
NS len, space; \
|
||||||
|
NIM_CHAR data[length + 1]; \
|
||||||
|
} name = {length, length, str}
|
||||||
|
|
||||||
|
typedef struct TStringDesc* string;
|
||||||
|
|
||||||
|
/* declared size of a sequence: */
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define SEQ_DECL_SIZE /* empty is correct! */
|
||||||
|
#else
|
||||||
|
# define SEQ_DECL_SIZE 1000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALLOC_0(size) calloc(1, size)
|
||||||
|
#define DL_ALLOC_0(size) dlcalloc(1, size)
|
||||||
|
|
||||||
|
#define GenericSeqSize sizeof(TGenericSeq)
|
||||||
|
#define paramCount() cmdCount
|
||||||
|
|
||||||
|
#ifndef NAN
|
||||||
|
# define NAN (0.0 / 0.0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INF
|
||||||
|
# ifdef INFINITY
|
||||||
|
# define INF INFINITY
|
||||||
|
# elif defined(HUGE_VAL)
|
||||||
|
# define INF HUGE_VAL
|
||||||
|
# else
|
||||||
|
# define INF (1.0 / 0.0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
typedef struct TSafePoint TSafePoint;
|
||||||
|
struct TSafePoint {
|
||||||
|
NS exc;
|
||||||
|
NCSTRING excname;
|
||||||
|
NCSTRING msg;
|
||||||
|
TSafePoint* prev;
|
||||||
|
jmp_buf context;
|
||||||
|
}; */
|
||||||
|
|
||||||
|
typedef struct TFrame TFrame;
|
||||||
|
struct TFrame {
|
||||||
|
TFrame* prev;
|
||||||
|
NCSTRING procname;
|
||||||
|
NS line;
|
||||||
|
NCSTRING filename;
|
||||||
|
NS len;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TFrame* volatile framePtr;
|
||||||
|
/*extern TSafePoint* volatile excHandler; */
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
struct NimException {
|
||||||
|
TSafePoint sp;
|
||||||
|
|
||||||
|
NimException(NS aExc, NCSTRING aExcname, NCSTRING aMsg) {
|
||||||
|
sp.exc = aExc; sp.excname = aExcname; sp.msg = aMsg;
|
||||||
|
sp.prev = excHandler;
|
||||||
|
excHandler = &sp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct TStringDesc {
|
||||||
|
NS len;
|
||||||
|
NS space;
|
||||||
|
NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */
|
||||||
|
} TStringDesc;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NS len, space;
|
||||||
|
} TGenericSeq;
|
||||||
|
|
||||||
|
typedef TGenericSeq* PGenericSeq;
|
||||||
|
|
||||||
|
#endif
|
||||||
39
lib/optparse.nim
Executable file
39
lib/optparse.nim
Executable file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
## This module provides a command line parser.
|
||||||
|
## It supports one iterator over all command line options.
|
||||||
|
|
||||||
|
#interface
|
||||||
|
|
||||||
|
{.push debugger: off.}
|
||||||
|
|
||||||
|
import
|
||||||
|
os
|
||||||
|
|
||||||
|
proc findSep(s: string): int {.nostatic.} =
|
||||||
|
for i in 0 .. high(s)-1:
|
||||||
|
if s[i] in {'=', ':'}: return i
|
||||||
|
return high(s)+1
|
||||||
|
|
||||||
|
iterator getopt*(): tuple[string, string] =
|
||||||
|
# returns a (cmd, arg) tuple.
|
||||||
|
for k in 1 .. ParamCount():
|
||||||
|
var param = paramStr(k)
|
||||||
|
if param[0] == '-':
|
||||||
|
var j = findSep(param)
|
||||||
|
cmd = copy(param, 0, j-1)
|
||||||
|
arg = copy(param, j+1)
|
||||||
|
else:
|
||||||
|
cmd = ""
|
||||||
|
arg = param
|
||||||
|
yield cmd, arg
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
939
lib/os.nim
Executable file
939
lib/os.nim
Executable file
|
|
@ -0,0 +1,939 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Basic operating system facilities like retrieving environment variables,
|
||||||
|
## reading command line arguments, working with directories, running shell
|
||||||
|
## commands, etc. This module is -- like any other basic library --
|
||||||
|
## platform independant.
|
||||||
|
|
||||||
|
{.push debugger:off.}
|
||||||
|
|
||||||
|
import
|
||||||
|
strutils, times
|
||||||
|
|
||||||
|
# copied from excpt.nim, because I don't want to make this template public
|
||||||
|
template newException(exceptn, message: expr): expr =
|
||||||
|
block: # open a new scope
|
||||||
|
var
|
||||||
|
e: ref exceptn
|
||||||
|
new(e)
|
||||||
|
e.msg = message
|
||||||
|
e
|
||||||
|
|
||||||
|
when defined(windows) or defined(OS2) or defined(DOS):
|
||||||
|
{.define: doslike.} # DOS-like filesystem
|
||||||
|
|
||||||
|
when defined(Nimdoc): # only for proper documentation:
|
||||||
|
const
|
||||||
|
CurDir* = '.'
|
||||||
|
## The constant string used by the operating system to refer to the
|
||||||
|
## current directory.
|
||||||
|
##
|
||||||
|
## For example: '.' for POSIX or ':' for the classic Macintosh.
|
||||||
|
|
||||||
|
ParDir* = ".."
|
||||||
|
## The constant string used by the operating system to refer to the parent
|
||||||
|
## directory.
|
||||||
|
##
|
||||||
|
## For example: ".." for POSIX or "::" for the classic Macintosh.
|
||||||
|
|
||||||
|
DirSep* = '/'
|
||||||
|
## The character used by the operating system to separate pathname
|
||||||
|
## components, for example, '/' for POSIX or ':' for the classic
|
||||||
|
## Macintosh.
|
||||||
|
##
|
||||||
|
## Note that knowing this is not sufficient to be able to parse or
|
||||||
|
## concatenate pathnames -- use `splitPath` and `joinPath` instead --
|
||||||
|
## but it is occasionally useful.
|
||||||
|
|
||||||
|
AltSep* = '/'
|
||||||
|
## An alternative character used by the operating system to separate
|
||||||
|
## pathname components, or the same as `DirSep` if only one separator
|
||||||
|
## character exists. This is set to '/' on Windows systems where `DirSep`
|
||||||
|
## is a backslash.
|
||||||
|
|
||||||
|
PathSep* = ':'
|
||||||
|
## The character conventionally used by the operating system to separate
|
||||||
|
## search patch components (as in PATH), such as ':' for POSIX or ';' for
|
||||||
|
## Windows.
|
||||||
|
|
||||||
|
FileSystemCaseSensitive* = True
|
||||||
|
## True if the file system is case sensitive, false otherwise. Used by
|
||||||
|
## `cmpPaths` to compare filenames properly.
|
||||||
|
|
||||||
|
elif defined(macos):
|
||||||
|
const
|
||||||
|
curdir* = ':'
|
||||||
|
pardir* = "::"
|
||||||
|
dirsep* = ':'
|
||||||
|
altsep* = dirsep
|
||||||
|
pathsep* = ','
|
||||||
|
FileSystemCaseSensitive* = false
|
||||||
|
|
||||||
|
# MacOS paths
|
||||||
|
# ===========
|
||||||
|
# MacOS directory separator is a colon ":" which is the only character not
|
||||||
|
# allowed in filenames.
|
||||||
|
#
|
||||||
|
# A path containing no colon or which begins with a colon is a partial path.
|
||||||
|
# E.g. ":kalle:petter" ":kalle" "kalle"
|
||||||
|
#
|
||||||
|
# All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
|
||||||
|
# When generating paths, one is safe if one ensures that all partial paths
|
||||||
|
# begin with a colon, and all full paths end with a colon.
|
||||||
|
# In full paths the first name (e g HD above) is the name of a mounted
|
||||||
|
# volume.
|
||||||
|
# These names are not unique, because, for instance, two diskettes with the
|
||||||
|
# same names could be inserted. This means that paths on MacOS is not
|
||||||
|
# waterproof. In case of equal names the first volume found will do.
|
||||||
|
# Two colons "::" are the relative path to the parent. Three is to the
|
||||||
|
# grandparent etc.
|
||||||
|
elif defined(doslike):
|
||||||
|
const
|
||||||
|
curdir* = '.'
|
||||||
|
pardir* = ".."
|
||||||
|
dirsep* = '\\' # seperator within paths
|
||||||
|
altsep* = '/'
|
||||||
|
pathSep* = ';' # seperator between paths
|
||||||
|
FileSystemCaseSensitive* = false
|
||||||
|
elif defined(PalmOS) or defined(MorphOS):
|
||||||
|
const
|
||||||
|
dirsep* = '/'
|
||||||
|
altsep* = dirsep
|
||||||
|
PathSep* = ';'
|
||||||
|
pardir* = ".."
|
||||||
|
FileSystemCaseSensitive* = false
|
||||||
|
elif defined(RISCOS):
|
||||||
|
const
|
||||||
|
dirsep* = '.'
|
||||||
|
altsep* = '.'
|
||||||
|
pardir* = ".." # is this correct?
|
||||||
|
pathSep* = ','
|
||||||
|
FileSystemCaseSensitive* = true
|
||||||
|
else: # UNIX-like operating system
|
||||||
|
const
|
||||||
|
curdir* = '.'
|
||||||
|
pardir* = ".."
|
||||||
|
dirsep* = '/'
|
||||||
|
altsep* = dirsep
|
||||||
|
pathSep* = ':'
|
||||||
|
FileSystemCaseSensitive* = true
|
||||||
|
|
||||||
|
const
|
||||||
|
ExtSep* = '.'
|
||||||
|
## The character which separates the base filename from the extension;
|
||||||
|
## for example, the '.' in ``os.nim``.
|
||||||
|
|
||||||
|
proc getApplicationDir*(): string {.noSideEffect.}
|
||||||
|
## Gets the directory of the application's executable.
|
||||||
|
|
||||||
|
proc getApplicationFilename*(): string {.noSideEffect.}
|
||||||
|
## Gets the filename of the application's executable.
|
||||||
|
|
||||||
|
proc getCurrentDir*(): string {.noSideEffect.}
|
||||||
|
## Gets the current working directory.
|
||||||
|
|
||||||
|
proc setCurrentDir*(newDir: string) {.inline.}
|
||||||
|
## Sets the current working directory; `EOS` is raised if
|
||||||
|
## `newDir` cannot been set.
|
||||||
|
|
||||||
|
proc getHomeDir*(): string {.noSideEffect.}
|
||||||
|
## Gets the home directory of the current user.
|
||||||
|
|
||||||
|
proc getConfigDir*(): string {.noSideEffect.}
|
||||||
|
## Gets the config directory of the current user for applications.
|
||||||
|
|
||||||
|
proc expandFilename*(filename: string): string
|
||||||
|
## Returns the full path of `filename`, "" on error.
|
||||||
|
|
||||||
|
proc ExistsFile*(filename: string): bool
|
||||||
|
## Returns true if the file exists, false otherwise.
|
||||||
|
|
||||||
|
proc JoinPath*(head, tail: string): string {.noSideEffect.}
|
||||||
|
## Joins two directory names to one.
|
||||||
|
##
|
||||||
|
## For example on Unix::
|
||||||
|
##
|
||||||
|
## JoinPath("usr", "lib")
|
||||||
|
##
|
||||||
|
## results in::
|
||||||
|
##
|
||||||
|
## "usr/lib"
|
||||||
|
##
|
||||||
|
## If head is the empty string, tail is returned.
|
||||||
|
## If tail is the empty string, head is returned.
|
||||||
|
|
||||||
|
proc `/` * (head, tail: string): string {.noSideEffect.} =
|
||||||
|
## The same as ``joinPath(head, tail)``
|
||||||
|
return joinPath(head, tail)
|
||||||
|
|
||||||
|
proc JoinPath*(parts: openarray[string]): string {.noSideEffect.}
|
||||||
|
## The same as `JoinPath(head, tail)`, but works with any number
|
||||||
|
## of directory parts.
|
||||||
|
|
||||||
|
proc SplitPath*(path: string, head, tail: var string) {.noSideEffect.}
|
||||||
|
## Splits a directory into (head, tail), so that
|
||||||
|
## ``JoinPath(head, tail) == path``.
|
||||||
|
##
|
||||||
|
## Example: After ``SplitPath("usr/local/bin", head, tail)``,
|
||||||
|
## `head` is "usr/local" and `tail` is "bin".
|
||||||
|
## Example: After ``SplitPath("usr/local/bin/", head, tail)``,
|
||||||
|
## `head` is "usr/local/bin" and `tail` is "".
|
||||||
|
|
||||||
|
proc parentDir*(path: string): string {.noSideEffect.}
|
||||||
|
## Returns the parent directory of `path`.
|
||||||
|
##
|
||||||
|
## This is often the same as the ``head`` result of ``splitPath``.
|
||||||
|
## If there is no parent, ``path`` is returned.
|
||||||
|
## Example: ``parentDir("/usr/local/bin") == "/usr/local"``.
|
||||||
|
## Example: ``parentDir("/usr/local/bin/") == "/usr/local"``.
|
||||||
|
|
||||||
|
proc `/../` * (head, tail: string): string {.noSideEffect.} =
|
||||||
|
## The same as ``parentDir(head) / tail``
|
||||||
|
return parentDir(head) / tail
|
||||||
|
|
||||||
|
proc UnixToNativePath*(path: string): string {.noSideEffect.}
|
||||||
|
## Converts an UNIX-like path to a native one.
|
||||||
|
##
|
||||||
|
## On an UNIX system this does nothing. Else it converts
|
||||||
|
## '/', '.', '..' to the appropriate things.
|
||||||
|
|
||||||
|
proc SplitFilename*(filename: string, name, extension: var string) {.
|
||||||
|
noSideEffect.}
|
||||||
|
## Splits a filename into (name, extension), so that
|
||||||
|
## ``name & extension == filename``.
|
||||||
|
##
|
||||||
|
## Example: After ``SplitFilename("usr/local/nimrodc.html", name, ext)``,
|
||||||
|
## `name` is "usr/local/nimrodc" and `ext` is ".html".
|
||||||
|
## It the file has no extension, extention is the empty string.
|
||||||
|
|
||||||
|
proc extractDir*(path: string): string {.noSideEffect.}
|
||||||
|
## Extracts the directory of a given path. This is the `head`
|
||||||
|
## result of `splitPath`.
|
||||||
|
|
||||||
|
proc extractFilename*(path: string): string {.noSideEffect.}
|
||||||
|
## Extracts the filename of a given `path`. This the the `tail`
|
||||||
|
## result of `splitPath`.
|
||||||
|
# XXX: this is not true: /usr/lib/ --> filename should be empty!
|
||||||
|
|
||||||
|
proc cmpPaths*(pathA, pathB: string): int {.noSideEffect.}
|
||||||
|
## Compares two paths.
|
||||||
|
##
|
||||||
|
## On a case-sensitive filesystem this is done
|
||||||
|
## case-sensitively otherwise case-insensitively. Returns:
|
||||||
|
##
|
||||||
|
## | 0 iff pathA == pathB
|
||||||
|
## | < 0 iff pathA < pathB
|
||||||
|
## | > 0 iff pathA > pathB
|
||||||
|
|
||||||
|
proc AppendFileExt*(filename, ext: string): string {.noSideEffect.}
|
||||||
|
## Appends the file extension `ext` to the `filename`, even if
|
||||||
|
## the `filename` already has an extension.
|
||||||
|
##
|
||||||
|
## `Ext` should be given without the leading '.', because some
|
||||||
|
## filesystems may use a different character.
|
||||||
|
## (Although I know of none such beast.)
|
||||||
|
|
||||||
|
proc ChangeFileExt*(filename, ext: string): string {.noSideEffect.}
|
||||||
|
## Changes the file extension to `ext`.
|
||||||
|
##
|
||||||
|
## If the `filename` has no extension, `ext` will be added.
|
||||||
|
## If `ext` == "" then the filename will get no extension.
|
||||||
|
## `Ext` should be given without the leading '.', because some
|
||||||
|
## filesystems may use a different character. (Although I know
|
||||||
|
## of none such beast.)
|
||||||
|
|
||||||
|
# procs dealing with processes:
|
||||||
|
proc executeProcess*(command: string): int
|
||||||
|
## Executes a process.
|
||||||
|
##
|
||||||
|
## Command has the form 'program args' where args are the command
|
||||||
|
## line arguments given to program. The proc returns the error code
|
||||||
|
## of the process when it has finished. The proc does not return
|
||||||
|
## until the process has finished.
|
||||||
|
|
||||||
|
proc executeShellCommand*(command: string): int
|
||||||
|
## Executes a shell command.
|
||||||
|
##
|
||||||
|
## The syntax of the command is unspecified and depends on the used
|
||||||
|
## shell. The proc returns the error code of the shell when it has finished.
|
||||||
|
|
||||||
|
# procs operating on a high level for files:
|
||||||
|
proc copyFile*(dest, source: string)
|
||||||
|
## Copies a file from `dest` to `source`. If this fails,
|
||||||
|
## `EOS` is raised.
|
||||||
|
|
||||||
|
proc moveFile*(dest, source: string)
|
||||||
|
## Moves a file from `dest` to `source`. If this fails, `EOS` is raised.
|
||||||
|
|
||||||
|
proc removeFile*(file: string)
|
||||||
|
## Removes the `file`. If this fails, `EOS` is raised.
|
||||||
|
|
||||||
|
proc removeDir*(dir: string)
|
||||||
|
## Removes the directory `dir` including all subdirectories or files
|
||||||
|
## in `dir` (recursively). If this fails, `EOS` is raised.
|
||||||
|
|
||||||
|
proc createDir*(dir: string)
|
||||||
|
## Creates the directory `dir`.
|
||||||
|
##
|
||||||
|
## The directory may contain several
|
||||||
|
## subdirectories that do not exist yet. The full path is created. If this
|
||||||
|
## fails, `EOS` is raised. It does NOT fail if the path already exists
|
||||||
|
## because for most usages this does not indicate an error.
|
||||||
|
|
||||||
|
proc existsDir*(dir: string): bool
|
||||||
|
## Returns true iff the directory `dir` exists. If `dir` is a file, false
|
||||||
|
## is returned.
|
||||||
|
|
||||||
|
proc getLastModificationTime*(file: string): TTime
|
||||||
|
## Gets the time of the `file`'s last modification.
|
||||||
|
|
||||||
|
# procs dealing with environment variables:
|
||||||
|
proc putEnv*(key, val: string)
|
||||||
|
## Sets the value of the environment variable named `key` to `val`.
|
||||||
|
## If an error occurs, `EInvalidEnvVar` is raised.
|
||||||
|
|
||||||
|
proc getEnv*(key: string): string
|
||||||
|
## Gets the value of the environment variable named `key`.
|
||||||
|
##
|
||||||
|
## If the variable does not exist, "" is returned. To distinguish
|
||||||
|
## whether a variable exists or it's value is just "", call
|
||||||
|
## `existsEnv(key)`.
|
||||||
|
|
||||||
|
proc existsEnv*(key: string): bool
|
||||||
|
## Checks whether the environment variable named `key` exists.
|
||||||
|
## Returns true if it exists, false otherwise.
|
||||||
|
|
||||||
|
# procs dealing with command line arguments:
|
||||||
|
proc paramCount*(): int
|
||||||
|
## Returns the number of command line arguments given to the
|
||||||
|
## application.
|
||||||
|
|
||||||
|
proc paramStr*(i: int): string
|
||||||
|
## Returns the `i`-th command line arguments given to the
|
||||||
|
## application.
|
||||||
|
##
|
||||||
|
## `i` should be in the range `1..paramCount()`, else
|
||||||
|
## the `EOutOfIndex` exception is raised.
|
||||||
|
|
||||||
|
# implementation
|
||||||
|
|
||||||
|
proc UnixToNativePath(path: string): string =
|
||||||
|
when defined(unix):
|
||||||
|
result = path
|
||||||
|
else:
|
||||||
|
var start: int
|
||||||
|
if path[0] == '/':
|
||||||
|
# an absolute path
|
||||||
|
when defined(doslike):
|
||||||
|
result = r"C:\"
|
||||||
|
elif defined(macos):
|
||||||
|
result = "" # must not start with ':'
|
||||||
|
else:
|
||||||
|
result = $dirSep
|
||||||
|
start = 1
|
||||||
|
elif path[0] == '.' and path[1] == '/':
|
||||||
|
# current directory
|
||||||
|
result = $curdir
|
||||||
|
start = 2
|
||||||
|
else:
|
||||||
|
result = ""
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
var i = start
|
||||||
|
while i < len(path): # ../../../ --> ::::
|
||||||
|
if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
|
||||||
|
# parent directory
|
||||||
|
when defined(macos):
|
||||||
|
if result[high(result)] == ':':
|
||||||
|
add result, ':'
|
||||||
|
else:
|
||||||
|
add result, pardir
|
||||||
|
else:
|
||||||
|
add result, pardir & dirSep
|
||||||
|
inc(i, 3)
|
||||||
|
elif path[i] == '/':
|
||||||
|
add result, dirSep
|
||||||
|
inc(i)
|
||||||
|
else:
|
||||||
|
add result, $path[i]
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
# interface to C library:
|
||||||
|
|
||||||
|
type
|
||||||
|
TStat {.importc: "struct stat".} = record
|
||||||
|
st_dev: int16
|
||||||
|
st_ino: int16
|
||||||
|
st_mode: int16
|
||||||
|
st_nlink: int16
|
||||||
|
st_uid: int16
|
||||||
|
st_gid: int16
|
||||||
|
st_rdev: int32
|
||||||
|
st_size: int32
|
||||||
|
st_atime: TTime
|
||||||
|
st_mtime: TTime
|
||||||
|
st_ctime: TTime
|
||||||
|
|
||||||
|
var
|
||||||
|
errno {.importc: "errno", header: "<errno.h>".}: cint
|
||||||
|
EEXIST {.importc: "EEXIST", header: "<errno.h>".}: cint
|
||||||
|
|
||||||
|
when defined(unix):
|
||||||
|
const dirHeader = "<sys/stat.h>"
|
||||||
|
elif defined(windows):
|
||||||
|
const dirHeader = "<direct.h>"
|
||||||
|
else:
|
||||||
|
{.error: "os library not ported to your OS. Please help!".}
|
||||||
|
|
||||||
|
|
||||||
|
proc chdir(path: CString): cint {.importc: "chdir", header: dirHeader.}
|
||||||
|
|
||||||
|
when defined(unix):
|
||||||
|
proc mkdir(dir: CString, theAccess: cint): cint {.
|
||||||
|
importc: "mkdir", header: dirHeader.}
|
||||||
|
proc realpath(name, resolved: CString): CString {.
|
||||||
|
importc: "realpath", header: "<stdlib.h>".}
|
||||||
|
proc getcwd(buf: CString, buflen: cint): CString {.
|
||||||
|
importc: "getcwd", header: "<unistd.h>".}
|
||||||
|
elif defined(windows):
|
||||||
|
proc mkdir(dir: CString): cint {.
|
||||||
|
importc: "mkdir", header: dirHeader.}
|
||||||
|
proc fullpath(buffer, file: CString, size: int): CString {.
|
||||||
|
importc: "_fullpath", header: "<stdlib.h>".}
|
||||||
|
proc getcwd(buf: CString, buflen: cint): CString {.
|
||||||
|
importc: "getcwd", header: "<direct.h>".}
|
||||||
|
|
||||||
|
proc CreateDirectory(pathName: cstring, security: Pointer): cint {.
|
||||||
|
importc: "CreateDirectory", header: "<windows.h>".}
|
||||||
|
proc GetLastError(): cint {.importc, header: "<windows.h>".}
|
||||||
|
else:
|
||||||
|
{.error: "os library not ported to your OS. Please help!".}
|
||||||
|
|
||||||
|
|
||||||
|
proc rmdir(dir: CString): cint {.importc: "rmdir", header: "<time.h>".}
|
||||||
|
# rmdir is of course in ``dirHeader``, but we check here to include
|
||||||
|
# time.h which is needed for stat(). stat() needs time.h and
|
||||||
|
# sys/stat.h; we workaround a C library issue here.
|
||||||
|
|
||||||
|
proc free(c: cstring) {.importc: "free", nodecl.}
|
||||||
|
# some C procs return a buffer that has to be freed with free(),
|
||||||
|
# so we define it here
|
||||||
|
proc strlen(str: CString): int {.importc: "strlen", nodecl.}
|
||||||
|
|
||||||
|
proc stat(f: CString, res: var TStat): cint {.
|
||||||
|
importc: "stat", header: "<sys/stat.h>".}
|
||||||
|
|
||||||
|
proc sameFile*(path1, path2: string): bool =
|
||||||
|
## Returns True if both pathname arguments refer to the same file or
|
||||||
|
## directory (as indicated by device number and i-node number).
|
||||||
|
## Raises an exception if an os.stat() call on either pathname fails.
|
||||||
|
var
|
||||||
|
a, b: TStat
|
||||||
|
if stat(path1, a) < 0 or stat(path2, b) < 0:
|
||||||
|
raise newException(EOS, "stat() call failed")
|
||||||
|
return int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
proc getModuleFilename(handle: int32, buf: CString, size: int32): int32 {.
|
||||||
|
importc: "GetModuleFileName", header: "<windows.h>".}
|
||||||
|
|
||||||
|
proc getLastModificationTime(file: string): TTime =
|
||||||
|
var
|
||||||
|
res: TStat
|
||||||
|
discard stat(file, res)
|
||||||
|
return res.st_mtime
|
||||||
|
|
||||||
|
proc setCurrentDir(newDir: string) =
|
||||||
|
if chdir(newDir) != 0:
|
||||||
|
raise newException(EOS, "cannot change the working directory to '$1'" %
|
||||||
|
newDir)
|
||||||
|
|
||||||
|
when defined(linux) or defined(solaris) or defined(bsd):
|
||||||
|
proc readlink(link, buf: cstring, size: int): int {.
|
||||||
|
header: "<unistd.h>", cdecl.}
|
||||||
|
|
||||||
|
proc getApplAux(procPath: string): string =
|
||||||
|
result = newString(256)
|
||||||
|
var len = readlink(procPath, result, 256)
|
||||||
|
if len > 256:
|
||||||
|
result = newString(len+1)
|
||||||
|
len = readlink(procPath, result, len)
|
||||||
|
setlen(result, len)
|
||||||
|
|
||||||
|
when defined(solaris) or defined(bsd):
|
||||||
|
proc getpid(): int {.importc, header: "<unistd.h>", cdecl.}
|
||||||
|
|
||||||
|
proc getApplicationFilename(): string =
|
||||||
|
# Linux: /proc/<pid>/exe
|
||||||
|
# Solaris:
|
||||||
|
# /proc/<pid>/object/a.out (filename only)
|
||||||
|
# /proc/<pid>/path/a.out (complete pathname)
|
||||||
|
# *BSD (and maybe Darwing too):
|
||||||
|
# /proc/<pid>/file
|
||||||
|
when defined(windows):
|
||||||
|
result = newString(256)
|
||||||
|
var len = getModuleFileName(0, result, 256)
|
||||||
|
setlen(result, int(len))
|
||||||
|
elif defined(linux):
|
||||||
|
result = getApplAux("/proc/self/exe")
|
||||||
|
elif defined(solaris):
|
||||||
|
result = getApplAux("/proc/" & $getpid() & "/path/a.out")
|
||||||
|
elif defined(bsd):
|
||||||
|
result = getApplAux("/proc/" & $getpid() & "file")
|
||||||
|
else:
|
||||||
|
# little heuristic that may work on other POSIX-like systems:
|
||||||
|
result = getEnv("_")
|
||||||
|
if len(result) == 0:
|
||||||
|
result = ParamStr(0) # POSIX guaranties that this contains the executable
|
||||||
|
# as it has been executed by the calling process
|
||||||
|
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
||||||
|
# iterate over any path in the $PATH environment variable
|
||||||
|
for p in split(getEnv("PATH"), {PathSep}):
|
||||||
|
var x = joinPath(p, result)
|
||||||
|
if ExistsFile(x): return x
|
||||||
|
|
||||||
|
{.push warnings: off.}
|
||||||
|
proc getApplicationDir(): string =
|
||||||
|
var tail: string
|
||||||
|
splitPath(getApplicationFilename(), result, tail)
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc getCurrentDir(): string =
|
||||||
|
const
|
||||||
|
bufsize = 512 # should be enough
|
||||||
|
result = newString(bufsize)
|
||||||
|
if getcwd(result, bufsize) != nil:
|
||||||
|
setlen(result, strlen(result))
|
||||||
|
else:
|
||||||
|
raise newException(EOS, "getcwd failed")
|
||||||
|
|
||||||
|
proc JoinPath(head, tail: string): string =
|
||||||
|
if len(head) == 0:
|
||||||
|
result = tail
|
||||||
|
elif head[len(head)-1] in {DirSep, AltSep}:
|
||||||
|
if tail[0] in {DirSep, AltSep}:
|
||||||
|
result = head & copy(tail, 1)
|
||||||
|
else:
|
||||||
|
result = head & tail
|
||||||
|
else:
|
||||||
|
if tail[0] in {DirSep, AltSep}:
|
||||||
|
result = head & tail
|
||||||
|
else:
|
||||||
|
result = head & DirSep & tail
|
||||||
|
|
||||||
|
proc JoinPath(parts: openarray[string]): string =
|
||||||
|
result = parts[0]
|
||||||
|
for i in 1..high(parts):
|
||||||
|
result = JoinPath(result, parts[i])
|
||||||
|
|
||||||
|
proc parentDir(path: string): string =
|
||||||
|
var
|
||||||
|
sepPos = -1
|
||||||
|
q = 1
|
||||||
|
if path[len(path)-1] in {dirsep, altsep}:
|
||||||
|
q = 2
|
||||||
|
for i in countdown(len(path)-q, 0):
|
||||||
|
if path[i] in {dirsep, altsep}:
|
||||||
|
sepPos = i
|
||||||
|
break
|
||||||
|
if sepPos >= 0:
|
||||||
|
result = copy(path, 0, sepPos-1)
|
||||||
|
else:
|
||||||
|
result = path
|
||||||
|
|
||||||
|
proc SplitPath(path: string, head, tail: var string) =
|
||||||
|
var
|
||||||
|
sepPos = -1
|
||||||
|
for i in countdown(len(path)-1, 0):
|
||||||
|
if path[i] in {dirsep, altsep}:
|
||||||
|
sepPos = i
|
||||||
|
break
|
||||||
|
if sepPos >= 0:
|
||||||
|
head = copy(path, 0, sepPos-1)
|
||||||
|
tail = copy(path, sepPos+1)
|
||||||
|
else:
|
||||||
|
head = ""
|
||||||
|
tail = path # make a string copy here
|
||||||
|
|
||||||
|
# helper:
|
||||||
|
proc searchExtPos(s: string): int =
|
||||||
|
result = -1
|
||||||
|
for i in countdown(len(s)-1, 0):
|
||||||
|
if s[i] == extsep:
|
||||||
|
result = i
|
||||||
|
break
|
||||||
|
elif s[i] in {dirsep, altsep}:
|
||||||
|
break # do not skip over path
|
||||||
|
|
||||||
|
proc SplitFilename(filename: string, name, extension: var string) =
|
||||||
|
var
|
||||||
|
extPos = searchExtPos(filename)
|
||||||
|
if extPos >= 0:
|
||||||
|
name = copy(filename, 0, extPos-1)
|
||||||
|
extension = copy(filename, extPos)
|
||||||
|
else:
|
||||||
|
name = filename # make a string copy here
|
||||||
|
extension = ""
|
||||||
|
|
||||||
|
proc normExt(ext: string): string =
|
||||||
|
if ext == "" or ext[0] == extSep: result = ext # no copy needed here
|
||||||
|
else: result = extSep & ext
|
||||||
|
|
||||||
|
proc ChangeFileExt(filename, ext: string): string =
|
||||||
|
var
|
||||||
|
extPos = searchExtPos(filename)
|
||||||
|
if extPos < 0: result = filename & normExt(ext)
|
||||||
|
else: result = copy(filename, 0, extPos-1) & normExt(ext)
|
||||||
|
|
||||||
|
proc AppendFileExt(filename, ext: string): string =
|
||||||
|
var
|
||||||
|
extPos = searchExtPos(filename)
|
||||||
|
if extPos < 0: result = filename & normExt(ext)
|
||||||
|
else: result = filename #make a string copy here
|
||||||
|
|
||||||
|
# some more C things:
|
||||||
|
|
||||||
|
proc csystem(cmd: CString): cint {.importc: "system", noDecl.}
|
||||||
|
# is in <stdlib.h>!
|
||||||
|
|
||||||
|
when defined(wcc):
|
||||||
|
# everywhere it is in <stdlib.h>, except for Watcom C ...
|
||||||
|
proc cputenv(env: CString): cint {.importc: "putenv", header: "<process.h>".}
|
||||||
|
|
||||||
|
else: # is in <stdlib.h>
|
||||||
|
proc cputenv(env: CString): cint {.importc: "putenv", noDecl.}
|
||||||
|
|
||||||
|
proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.}
|
||||||
|
|
||||||
|
#long _findfirst(char *, struct _finddata_t *);
|
||||||
|
#int _findnext(long, struct _finddata_t *);
|
||||||
|
#int _findclose(long);
|
||||||
|
when defined(windows):
|
||||||
|
type
|
||||||
|
TFindData {.importc: "struct _finddata_t".} = record
|
||||||
|
attrib {.importc: "attrib".}: cint
|
||||||
|
time_create {.importc: "time_create".}: cint
|
||||||
|
time_access {.importc: "time_access".}: cint
|
||||||
|
time_write {.importc: "time_write".}: cint
|
||||||
|
size {.importc: "size".}: cint
|
||||||
|
name {.importc: "name".}: array[0..259, char]
|
||||||
|
|
||||||
|
proc findfirst(pathname: CString, f: ptr TFindData): cint {.
|
||||||
|
importc: "_findfirst", header: "<io.h>".}
|
||||||
|
proc findnext(handle: cint, f: ptr TFindData): cint {.
|
||||||
|
importc: "_findnext", header: "<io.h>".}
|
||||||
|
proc findclose(handle: cint) {.importc: "_findclose", header: "<io.h>".}
|
||||||
|
else:
|
||||||
|
type
|
||||||
|
TFindData {.importc: "glob_t".} = record
|
||||||
|
gl_pathc: int # count of paths matched by pattern
|
||||||
|
gl_pathv: ptr array[0..1000_000, CString] # list of matched path names
|
||||||
|
gl_offs: int # slots to reserve at beginning of gl_pathv
|
||||||
|
PFindData = ptr TFindData
|
||||||
|
|
||||||
|
proc glob(pattern: cstring, flags: cint, errfunc: pointer,
|
||||||
|
pglob: PFindData): cint {.
|
||||||
|
importc: "glob", header: "<glob.h>".}
|
||||||
|
|
||||||
|
proc globfree(pglob: PFindData) {.
|
||||||
|
importc: "globfree", header: "<glob.h>".}
|
||||||
|
|
||||||
|
proc cremove(filename: CString): cint {.importc: "remove", noDecl.}
|
||||||
|
proc crename(oldname, newname: CString): cint {.importc: "rename", noDecl.}
|
||||||
|
|
||||||
|
when defined(Windows):
|
||||||
|
proc cCopyFile(lpExistingFileName, lpNewFileName: CString,
|
||||||
|
bFailIfExists: cint): cint {.
|
||||||
|
importc: "CopyFile", header: "<windows.h>".}
|
||||||
|
# cMoveFile(lpExistingFileName, lpNewFileName: CString): int
|
||||||
|
# {.importc: "MoveFile", noDecl, header: "<winbase.h>".}
|
||||||
|
# cRemoveFile(filename: CString, cmo: int)
|
||||||
|
# {.importc: "DeleteFile", noDecl, header: "<winbase.h>".}
|
||||||
|
else:
|
||||||
|
# generic version of cCopyFile which works for any platform:
|
||||||
|
proc cCopyFile(lpExistingFileName, lpNewFileName: CString,
|
||||||
|
bFailIfExists: cint): cint =
|
||||||
|
const
|
||||||
|
bufSize = 8192 # 8K buffer
|
||||||
|
var
|
||||||
|
dest, src: TFile
|
||||||
|
if not openFile(src, $lpExistingFilename): return -1
|
||||||
|
if not openFile(dest, $lpNewFilename, fmWrite):
|
||||||
|
closeFile(src)
|
||||||
|
return -1
|
||||||
|
var
|
||||||
|
buf: Pointer = alloc(bufsize)
|
||||||
|
bytesread, byteswritten: int
|
||||||
|
while True:
|
||||||
|
bytesread = readBuffer(src, buf, bufsize)
|
||||||
|
byteswritten = writeBuffer(dest, buf, bytesread)
|
||||||
|
if bytesread != bufSize: break
|
||||||
|
if byteswritten == bytesread: result = 0
|
||||||
|
else: result = -1
|
||||||
|
dealloc(buf)
|
||||||
|
closeFile(src)
|
||||||
|
closeFile(dest)
|
||||||
|
|
||||||
|
|
||||||
|
proc moveFile(dest, source: string) =
|
||||||
|
if crename(source, dest) != 0:
|
||||||
|
raise newException(EOS, "cannot move file from '$1' to '$2'" %
|
||||||
|
[source, dest])
|
||||||
|
|
||||||
|
proc copyFile(dest, source: string) =
|
||||||
|
if cCopyFile(source, dest, 0) != 0:
|
||||||
|
raise newException(EOS, "cannot copy file from '$1' to '$2'" %
|
||||||
|
[source, dest])
|
||||||
|
|
||||||
|
proc removeFile(file: string) =
|
||||||
|
if cremove(file) != 0:
|
||||||
|
raise newException(EOS, "cannot remove file '$1'" % file)
|
||||||
|
|
||||||
|
proc removeDir(dir: string) =
|
||||||
|
if rmdir(dir) != 0:
|
||||||
|
raise newException(EOS, "cannot remove directory '$1'" % dir)
|
||||||
|
|
||||||
|
proc createDir(dir: string) =
|
||||||
|
when defined(unix):
|
||||||
|
if mkdir(dir, 0o711) != 0 and int(errno) != EEXIST:
|
||||||
|
raise newException(EOS, "cannot create directory '$1'" % dir)
|
||||||
|
else:
|
||||||
|
if CreateDirectory(dir, nil) == 0 and GetLastError() != 183:
|
||||||
|
raise newException(EOS, "cannot create directory '$1'" % dir)
|
||||||
|
|
||||||
|
proc existsDir(dir: string): bool =
|
||||||
|
var safe = getCurrentDir()
|
||||||
|
# just try to set the current dir to dir; if it works, it must exist:
|
||||||
|
result = chdir(dir) == 0
|
||||||
|
if result:
|
||||||
|
setCurrentDir(safe) # set back to the old working directory
|
||||||
|
|
||||||
|
proc executeProcess(command: string): int =
|
||||||
|
return csystem(command) # XXX: do this without shell
|
||||||
|
|
||||||
|
proc executeShellCommand(command: string): int =
|
||||||
|
return csystem(command)
|
||||||
|
|
||||||
|
var
|
||||||
|
envComputed: bool = false
|
||||||
|
environment {.noStatic.}: seq[string] = []
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
# because we support Windows GUI applications, things get really
|
||||||
|
# messy here...
|
||||||
|
proc GetEnvironmentStrings(): Pointer {.
|
||||||
|
importc: "GetEnvironmentStrings", header: "<windows.h>".}
|
||||||
|
proc FreeEnvironmentStrings(env: Pointer) {.
|
||||||
|
importc: "FreeEnvironmentStrings", header: "<windows.h>".}
|
||||||
|
proc strEnd(cstr: CString, c = 0): CString {.importc: "strchr", nodecl.}
|
||||||
|
|
||||||
|
proc getEnvVarsC() {.noStatic.} =
|
||||||
|
if not envComputed:
|
||||||
|
var
|
||||||
|
env = cast[CString](getEnvironmentStrings())
|
||||||
|
e = env
|
||||||
|
if e == nil: return # an error occured
|
||||||
|
while True:
|
||||||
|
var eend = strEnd(e)
|
||||||
|
add environment, $e
|
||||||
|
e = cast[CString](cast[TAddress](eend)+1)
|
||||||
|
if eend[1] == '\0': break
|
||||||
|
envComputed = true
|
||||||
|
FreeEnvironmentStrings(env)
|
||||||
|
|
||||||
|
else:
|
||||||
|
var
|
||||||
|
gEnv {.importc: "gEnv".}: ptr array [0..10_000, CString]
|
||||||
|
|
||||||
|
proc getEnvVarsC() {.noStatic.} =
|
||||||
|
# retrieves the variables of char** env of C's main proc
|
||||||
|
if not envComputed:
|
||||||
|
var
|
||||||
|
i: int = 0
|
||||||
|
while True:
|
||||||
|
if gEnv[i] == nil: break
|
||||||
|
add environment, $gEnv[i]
|
||||||
|
inc(i)
|
||||||
|
envComputed = true
|
||||||
|
|
||||||
|
proc findEnvVar(key: string): int =
|
||||||
|
getEnvVarsC()
|
||||||
|
var temp = key & '='
|
||||||
|
for i in 0..high(environment):
|
||||||
|
if findSubStr(temp, environment[i]) == 0: return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc getEnv(key: string): string =
|
||||||
|
var i = findEnvVar(key)
|
||||||
|
if i >= 0:
|
||||||
|
return copy(environment[i], findSubStr("=", environment[i])+1)
|
||||||
|
else:
|
||||||
|
var env = cgetenv(key)
|
||||||
|
if env == nil: return ""
|
||||||
|
result = $env
|
||||||
|
|
||||||
|
proc existsEnv(key: string): bool =
|
||||||
|
if cgetenv(key) != nil: return true
|
||||||
|
else: return findEnvVar(key) >= 0
|
||||||
|
|
||||||
|
iterator iterOverEnvironment*(): tuple[string, string] =
|
||||||
|
## Iterate over all environments varialbes. In the first component of the
|
||||||
|
## tuple is the name of the current variable stored, in the second its value.
|
||||||
|
getEnvVarsC()
|
||||||
|
for i in 0..high(environment):
|
||||||
|
var p = findSubStr("=", environment[i])
|
||||||
|
yield (copy(environment[i], 0, p-1), copy(environment[i], p+1))
|
||||||
|
|
||||||
|
proc putEnv(key, val: string) =
|
||||||
|
# Note: by storing the string in the environment sequence,
|
||||||
|
# we gurantee that we don't free the memory before the program
|
||||||
|
# ends (this is needed for POSIX compliance). It is also needed so that
|
||||||
|
# the process itself may access its modified environment variables!
|
||||||
|
var indx = findEnvVar(key)
|
||||||
|
if indx >= 0:
|
||||||
|
environment[indx] = key & '=' & val
|
||||||
|
else:
|
||||||
|
add environment, (key & '=' & val)
|
||||||
|
indx = high(environment)
|
||||||
|
if cputenv(environment[indx]) != 0:
|
||||||
|
raise newException(EOS, "attempt to set an invalid environment variable")
|
||||||
|
|
||||||
|
iterator walkFiles*(pattern: string): string =
|
||||||
|
## Iterate over all the files that match the `pattern`.
|
||||||
|
##
|
||||||
|
## `pattern` is OS dependant, but at least the "\*.ext"
|
||||||
|
## notation is supported.
|
||||||
|
when defined(windows):
|
||||||
|
var
|
||||||
|
f: TFindData
|
||||||
|
res: int
|
||||||
|
res = findfirst(pattern, addr(f))
|
||||||
|
if res != -1:
|
||||||
|
while true:
|
||||||
|
yield $f.name
|
||||||
|
if int(findnext(res, addr(f))) == -1: break
|
||||||
|
findclose(res)
|
||||||
|
else: # here we use glob
|
||||||
|
var
|
||||||
|
f: TFindData
|
||||||
|
res: int
|
||||||
|
f.gl_offs = 0
|
||||||
|
f.gl_pathc = 0
|
||||||
|
f.gl_pathv = nil
|
||||||
|
res = glob(pattern, 0, nil, addr(f))
|
||||||
|
if res != 0: raise newException(EOS, "walkFiles() failed")
|
||||||
|
for i in 0.. f.gl_pathc - 1:
|
||||||
|
assert(f.gl_pathv[i] != nil)
|
||||||
|
yield $f.gl_pathv[i]
|
||||||
|
globfree(addr(f))
|
||||||
|
|
||||||
|
{.push warnings:off.}
|
||||||
|
proc ExistsFile(filename: string): bool =
|
||||||
|
var
|
||||||
|
res: TStat
|
||||||
|
return stat(filename, res) >= 0
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc cmpPaths(pathA, pathB: string): int =
|
||||||
|
if FileSystemCaseSensitive:
|
||||||
|
result = cmp(pathA, pathB)
|
||||||
|
else:
|
||||||
|
result = cmpIgnoreCase(pathA, pathB)
|
||||||
|
|
||||||
|
proc extractDir(path: string): string =
|
||||||
|
var
|
||||||
|
tail: string
|
||||||
|
splitPath(path, result, tail)
|
||||||
|
|
||||||
|
proc extractFilename(path: string): string =
|
||||||
|
var
|
||||||
|
head: string
|
||||||
|
splitPath(path, head, result)
|
||||||
|
|
||||||
|
proc expandFilename(filename: string): string =
|
||||||
|
# returns the full path of 'filename'; "" on error
|
||||||
|
var
|
||||||
|
res: CString
|
||||||
|
when defined(unix):
|
||||||
|
res = realpath(filename, nil)
|
||||||
|
else:
|
||||||
|
res = fullpath(nil, filename, 0)
|
||||||
|
if res == nil:
|
||||||
|
result = "" # an error occured
|
||||||
|
else:
|
||||||
|
result = $res
|
||||||
|
free(res)
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
proc GetHomeDir(): string = return getEnv("USERPROFILE") & "\\"
|
||||||
|
proc GetConfigDir(): string = return getEnv("APPDATA") & "\\"
|
||||||
|
|
||||||
|
# Since we support GUI applications with Nimrod, we sometimes generate
|
||||||
|
# a WinMain entry proc. But a WinMain proc has no access to the parsed
|
||||||
|
# command line arguments. The way to get them differs. Thus we parse them
|
||||||
|
# ourselves. This has the additional benefit that the program's behaviour
|
||||||
|
# is always the same -- independent of the used C compiler.
|
||||||
|
proc GetCommandLine(): CString {.
|
||||||
|
importc: "GetCommandLine", header: "<windows.h>".}
|
||||||
|
|
||||||
|
var
|
||||||
|
ownArgc: int = -1
|
||||||
|
ownArgv: seq[string] = []
|
||||||
|
|
||||||
|
proc parseCmdLine() =
|
||||||
|
if ownArgc != -1: return # already processed
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
j = 0
|
||||||
|
c = getCommandLine()
|
||||||
|
ownArgc = 0
|
||||||
|
while c[i] != '\0':
|
||||||
|
var a = ""
|
||||||
|
while c[i] >= '\1' and c[i] <= ' ': inc(i) # skip whitespace
|
||||||
|
case c[i]
|
||||||
|
of '\'', '\"':
|
||||||
|
var delim = c[i]
|
||||||
|
inc(i) # skip ' or "
|
||||||
|
while c[i] != '\0' and c[i] != delim:
|
||||||
|
add a, c[i]
|
||||||
|
inc(i)
|
||||||
|
if c[i] != '\0': inc(i)
|
||||||
|
else:
|
||||||
|
while c[i] > ' ':
|
||||||
|
add a, c[i]
|
||||||
|
inc(i)
|
||||||
|
add ownArgv, a
|
||||||
|
inc(ownArgc)
|
||||||
|
|
||||||
|
proc paramStr(i: int): string =
|
||||||
|
parseCmdLine()
|
||||||
|
if i < ownArgc and i >= 0:
|
||||||
|
return ownArgv[i]
|
||||||
|
raise newException(EInvalidIndex, "invalid index")
|
||||||
|
|
||||||
|
proc paramCount(): int =
|
||||||
|
parseCmdLine()
|
||||||
|
result = ownArgc-1
|
||||||
|
|
||||||
|
else:
|
||||||
|
proc GetHomeDir(): string = return getEnv("HOME") & "/"
|
||||||
|
proc GetConfigDir(): string = return getEnv("HOME") & "/"
|
||||||
|
|
||||||
|
var
|
||||||
|
cmdCount {.importc: "cmdCount".}: int
|
||||||
|
cmdLine {.importc: "cmdLine".}: cstringArray
|
||||||
|
|
||||||
|
proc paramStr(i: int): string =
|
||||||
|
if i < cmdCount and i >= 0: return $cmdLine[i]
|
||||||
|
raise newException(EInvalidIndex, "invalid index")
|
||||||
|
|
||||||
|
proc paramCount(): int = return cmdCount-1
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
1818
lib/posix/posix.nim
Executable file
1818
lib/posix/posix.nim
Executable file
File diff suppressed because it is too large
Load diff
35
lib/powerpc.asm.in
Executable file
35
lib/powerpc.asm.in
Executable file
|
|
@ -0,0 +1,35 @@
|
||||||
|
; This contains the CPU-dependant variants of some routines.
|
||||||
|
; (C) 2005 Andreas Rumpf
|
||||||
|
; This code was inspired by the Freepascal compiler's sources
|
||||||
|
; All routines here have the _cdecl calling convention because
|
||||||
|
; that is the only convention any C compiler supports.
|
||||||
|
|
||||||
|
\python{
|
||||||
|
def c(name):
|
||||||
|
if os.name == 'posix':
|
||||||
|
return name
|
||||||
|
else:
|
||||||
|
return "_" + name
|
||||||
|
}
|
||||||
|
|
||||||
|
segment code
|
||||||
|
|
||||||
|
global \c{cpu_inc_locked}
|
||||||
|
global \c{cpu_dec_locked}
|
||||||
|
|
||||||
|
\c{cpu_dec_locked}:
|
||||||
|
; input: address of arg in r3
|
||||||
|
.LDecLockedLoop:
|
||||||
|
lwarx r10,0,r3
|
||||||
|
subi r10,r10,1
|
||||||
|
stwcx. r10,0,r3
|
||||||
|
bne- .LDecLockedLoop
|
||||||
|
cntlzw r3,r10
|
||||||
|
srwi r3,r3,5
|
||||||
|
|
||||||
|
\c{cpu_inc_locked}:
|
||||||
|
.LIncLockedLoop:
|
||||||
|
lwarx r10,0,r3
|
||||||
|
addi r10,r10,1
|
||||||
|
stwcx. r10,0,r3
|
||||||
|
bne- .LIncLockedLoop
|
||||||
1009
lib/process.nim
Executable file
1009
lib/process.nim
Executable file
File diff suppressed because it is too large
Load diff
205
lib/ptrset.nim
Executable file
205
lib/ptrset.nim
Executable file
|
|
@ -0,0 +1,205 @@
|
||||||
|
# This implements a new pointer set. Access time O(1). For 32 bit systems, we
|
||||||
|
# currently need 3 memory accesses.
|
||||||
|
|
||||||
|
const
|
||||||
|
PageSize = 1024 * sizeof(int)
|
||||||
|
MemAlignment = 8 # minimal memory block that can be allocated
|
||||||
|
BitsPerUnit = sizeof(int)*8
|
||||||
|
# a "unit" is a word, i.e. 4 bytes
|
||||||
|
# on a 32 bit system; I do not use the term "word" because under 32-bit
|
||||||
|
# Windows it is sometimes only 16 bits
|
||||||
|
|
||||||
|
BitsPerPage = PageSize div MemAlignment
|
||||||
|
UnitsPerPage = BitsPerPage div BitsPerUnit
|
||||||
|
# how many units do we need to describe a page:
|
||||||
|
# on 32 bit systems this is only 16 (!)
|
||||||
|
|
||||||
|
type
|
||||||
|
PPointer = ptr pointer
|
||||||
|
|
||||||
|
TCollectorData = int
|
||||||
|
TCell = record
|
||||||
|
refcount: TCollectorData # the refcount and bit flags
|
||||||
|
typ: PNimType
|
||||||
|
stackcount: int # stack counter for debugging
|
||||||
|
drefc: int # real reference counter for debugging
|
||||||
|
|
||||||
|
PCell = ptr TCell
|
||||||
|
|
||||||
|
proc cellToUsr(cell: PCell): pointer {.inline.} =
|
||||||
|
# convert object (=pointer to refcount) to pointer to userdata
|
||||||
|
result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
|
||||||
|
|
||||||
|
proc usrToCell(usr: pointer): PCell {.inline.} =
|
||||||
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
|
result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
|
||||||
|
|
||||||
|
proc gcAlloc(size: int): pointer =
|
||||||
|
result = alloc0(size)
|
||||||
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
||||||
|
# ------------------ Zero count table (ZCT) and any table (AT) -------------
|
||||||
|
|
||||||
|
# this that has to equals zero, otherwise we have to round up UnitsPerPage:
|
||||||
|
when BitsPerPage mod BitsPerUnit != 0:
|
||||||
|
{.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
|
||||||
|
|
||||||
|
# ------------------- cell set handling ------------------------------
|
||||||
|
# A cellset consists of a hash table of page descriptors. A page
|
||||||
|
# descriptor has a bit for
|
||||||
|
# every Memalignment'th byte in the page.
|
||||||
|
# However, only bits corresponding to addresses that start memory blocks
|
||||||
|
# are set.
|
||||||
|
# Page descriptors are also linked to a list; the list
|
||||||
|
# is used for easy traversing of all page descriptors; this allows a
|
||||||
|
# fast iterator.
|
||||||
|
# We use a specialized hashing scheme; the formula is :
|
||||||
|
# hash = Page bitand max
|
||||||
|
# We use linear probing with the formular: (5*h)+1
|
||||||
|
# Thus we likely get no collisions at all if the pages are given to us
|
||||||
|
# in a sequential manner by the operating system!
|
||||||
|
const
|
||||||
|
bitsPerNode = 10 # we use 10 bits per node; this means 3 memory accesses on
|
||||||
|
# 32 bit systems
|
||||||
|
|
||||||
|
type
|
||||||
|
PPageDesc = ptr TPageDesc
|
||||||
|
|
||||||
|
TBitIndex = range[0..UnitsPerPage-1]
|
||||||
|
|
||||||
|
TPageDesc = record
|
||||||
|
next: PPageDesc # all nodes are connected with this pointer
|
||||||
|
key: TAddress # start address at bit 0
|
||||||
|
bits: array[TBitIndex, int] # a bit vector
|
||||||
|
|
||||||
|
PPageDescArray = ptr array[0..1000_000, PPageDesc]
|
||||||
|
TCellSet = record
|
||||||
|
counter, max: int
|
||||||
|
head: PPageDesc
|
||||||
|
data: PPageDescArray
|
||||||
|
|
||||||
|
TSetNode = record
|
||||||
|
n: array[0.. (1 shl bitsPerNode)-1, PSetNode]
|
||||||
|
PSetNode = ptr TSetNode
|
||||||
|
|
||||||
|
const
|
||||||
|
InitCellSetSize = 1024 # must be a power of two!
|
||||||
|
|
||||||
|
proc CellSetInit(s: var TCellSet) =
|
||||||
|
s.data = gcAlloc(InitCellSetSize * sizeof(PPageDesc))
|
||||||
|
s.max = InitCellSetSize-1
|
||||||
|
s.counter = 0
|
||||||
|
s.head = nil
|
||||||
|
|
||||||
|
proc CellSetDeinit(s: var TCellSet) =
|
||||||
|
var it = s.head
|
||||||
|
while it != nil:
|
||||||
|
var n = it.next
|
||||||
|
dealloc(it)
|
||||||
|
it = n
|
||||||
|
s.head = nil # play it safe here
|
||||||
|
dealloc(s.data)
|
||||||
|
s.data = nil
|
||||||
|
s.counter = 0
|
||||||
|
|
||||||
|
proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
|
||||||
|
var h = cast[int](key) and t.max
|
||||||
|
while t.data[h] != nil:
|
||||||
|
if t.data[h].key == key: return t.data[h]
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
proc CellSetRawInsert(t: TCellSet, data: PPageDescArray,
|
||||||
|
desc: PPageDesc) =
|
||||||
|
var h = cast[int](desc.key) and t.max
|
||||||
|
while data[h] != nil:
|
||||||
|
assert(data[h] != desc)
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
assert(data[h] == nil)
|
||||||
|
data[h] = desc
|
||||||
|
|
||||||
|
proc CellSetEnlarge(t: var TCellSet) =
|
||||||
|
var
|
||||||
|
n: PPageDescArray
|
||||||
|
oldMax = t.max
|
||||||
|
t.max = ((t.max+1)*2)-1
|
||||||
|
n = gcAlloc((t.max + 1) * sizeof(PPageDesc))
|
||||||
|
for i in 0 .. oldmax:
|
||||||
|
if t.data[i] != nil:
|
||||||
|
CellSetRawInsert(t, n, t.data[i])
|
||||||
|
dealloc(t.data)
|
||||||
|
t.data = n
|
||||||
|
|
||||||
|
proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
|
||||||
|
var h = cast[int](key) and t.max
|
||||||
|
while true:
|
||||||
|
var x = t.data[h]
|
||||||
|
if x == nil: break
|
||||||
|
if x.key == key: return x
|
||||||
|
h = nextTry(h, t.max)
|
||||||
|
|
||||||
|
if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t)
|
||||||
|
inc(t.counter)
|
||||||
|
h = cast[int](key) and t.max
|
||||||
|
while t.data[h] != nil: h = nextTry(h, t.max)
|
||||||
|
assert(t.data[h] == nil)
|
||||||
|
# the new page descriptor goes into result
|
||||||
|
result = gcAlloc(sizeof(TPageDesc))
|
||||||
|
result.next = t.head
|
||||||
|
result.key = key
|
||||||
|
t.head = result
|
||||||
|
t.data[h] = result
|
||||||
|
|
||||||
|
# ---------- slightly higher level procs ----------------------------------
|
||||||
|
|
||||||
|
proc in_Operator(s: TCellSet, cell: PCell): bool =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetGet(s, u /% PageSize)
|
||||||
|
if t != nil:
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0
|
||||||
|
else:
|
||||||
|
result = false
|
||||||
|
|
||||||
|
proc incl(s: var TCellSet, cell: PCell) =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetPut(s, u /% PageSize)
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or
|
||||||
|
(1 shl (u %% BitsPerUnit))
|
||||||
|
|
||||||
|
proc excl(s: var TCellSet, cell: PCell) =
|
||||||
|
var
|
||||||
|
u: TAddress
|
||||||
|
t: PPageDesc
|
||||||
|
u = cast[TAddress](cell)
|
||||||
|
t = CellSetGet(s, u /% PageSize)
|
||||||
|
if t != nil:
|
||||||
|
u = (u %% PageSize) /% MemAlignment
|
||||||
|
t.bits[u %% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and
|
||||||
|
not (1 shl (u %% BitsPerUnit)))
|
||||||
|
|
||||||
|
iterator elements(t: TCellSet): PCell {.inline.} =
|
||||||
|
# while traversing it is forbidden to add pointers to the tree!
|
||||||
|
var r = t.head
|
||||||
|
while r != nil:
|
||||||
|
var i = 0
|
||||||
|
while i <= high(r.bits):
|
||||||
|
var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
|
||||||
|
# modifying operations are not allowed during traversation
|
||||||
|
var j = 0
|
||||||
|
while w != 0: # test all remaining bits for zero
|
||||||
|
if (w and 1) != 0: # the bit is set!
|
||||||
|
yield cast[PCell]((r.key *% PageSize) +%
|
||||||
|
(i*%BitsPerUnit+%j) *% MemAlignment)
|
||||||
|
inc(j)
|
||||||
|
w = w shr 1
|
||||||
|
inc(i)
|
||||||
|
r = r.next
|
||||||
|
|
||||||
233
lib/repr.nim
Executable file
233
lib/repr.nim
Executable file
|
|
@ -0,0 +1,233 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# The generic ``repr`` procedure. It is an invaluable debugging tool.
|
||||||
|
|
||||||
|
#proc cstrToNimStrDummy(s: cstring): string {.inline.} =
|
||||||
|
# result = cast[string](cstrToNimStr(s))
|
||||||
|
|
||||||
|
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||||
|
proc reprFloat(x: float): string {.compilerproc.} = return $x
|
||||||
|
|
||||||
|
proc reprPointer(x: pointer): string {.compilerproc.} =
|
||||||
|
var buf: array [0..59, char]
|
||||||
|
c_sprintf(buf, "%p", x)
|
||||||
|
return $buf
|
||||||
|
|
||||||
|
proc reprStrAux(result: var string, s: string) =
|
||||||
|
if cast[pointer](s) == nil:
|
||||||
|
add result "nil"
|
||||||
|
return
|
||||||
|
add result, reprPointer(cast[pointer](s)) & "\""
|
||||||
|
for c in items(s):
|
||||||
|
case c
|
||||||
|
of '"': add result "\\\""
|
||||||
|
of '\\': add result, "\\\\" # BUGFIX: forgotten
|
||||||
|
of '\10': add result, "\\10\"\n\"" # " \n " # better readability
|
||||||
|
of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
|
||||||
|
add result, "\\" & reprInt(ord(c))
|
||||||
|
else: result.add(c)
|
||||||
|
add result, "\""
|
||||||
|
|
||||||
|
proc reprStr(s: string): string {.compilerproc.} =
|
||||||
|
result = ""
|
||||||
|
reprStrAux(result, s)
|
||||||
|
|
||||||
|
proc reprBool(x: bool): string {.compilerproc.} =
|
||||||
|
if x: result = "true"
|
||||||
|
else: result = "false"
|
||||||
|
|
||||||
|
proc reprChar(x: char): string {.compilerproc.} =
|
||||||
|
result = "\'"
|
||||||
|
case x
|
||||||
|
of '"': add result, "\\\""
|
||||||
|
of '\\': add result, "\\\\"
|
||||||
|
of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
|
||||||
|
else: add result, x
|
||||||
|
add result, "\'"
|
||||||
|
|
||||||
|
proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =
|
||||||
|
if e <% typ.node.len: # BUGFIX
|
||||||
|
result = $typ.node.sons[e].name
|
||||||
|
else:
|
||||||
|
result = $e & " (invalid data!)"
|
||||||
|
|
||||||
|
type
|
||||||
|
pbyteArray = ptr array[0.. 0xffff, byte]
|
||||||
|
|
||||||
|
proc addSetElem(result: var string, elem: int, typ: PNimType) =
|
||||||
|
case typ.kind
|
||||||
|
of tyEnum: add result, reprEnum(elem, typ)
|
||||||
|
of tyBool: add result, reprBool(bool(elem))
|
||||||
|
of tyChar: add result, reprChar(chr(elem))
|
||||||
|
of tyRange: addSetElem(result, elem, typ.base)
|
||||||
|
of tyInt..tyInt64: add result, reprInt(elem)
|
||||||
|
else: # data corrupt --> inform the user
|
||||||
|
add result, " (invalid data!)"
|
||||||
|
|
||||||
|
proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
|
||||||
|
# "typ.slots.len" field is for sets the "first" field
|
||||||
|
var elemCounter = 0 # we need this flag for adding the comma at
|
||||||
|
# the right places
|
||||||
|
add result, "{"
|
||||||
|
var u: int64
|
||||||
|
case typ.size
|
||||||
|
of 1: u = ze64(cast[ptr int8](p)^)
|
||||||
|
of 2: u = ze64(cast[ptr int16](p)^)
|
||||||
|
of 4: u = ze64(cast[ptr int32](p)^)
|
||||||
|
of 8: u = ze64(cast[ptr int64](p)^)
|
||||||
|
else:
|
||||||
|
var a = cast[pbyteArray](p)^
|
||||||
|
for i in 0 .. typ.size*8-1:
|
||||||
|
if (a[i div 8] and (1 shl (i mod 8))) != 0:
|
||||||
|
if elemCounter > 0: add result, ", "
|
||||||
|
addSetElem(result, i+typ.node.len, typ.base)
|
||||||
|
inc(elemCounter)
|
||||||
|
if typ.size <= 8:
|
||||||
|
for i in 0..sizeof(int64)*8-1:
|
||||||
|
if (u and (1 shl i)) != 0:
|
||||||
|
if elemCounter > 0: add result, ", "
|
||||||
|
addSetElem(result, i+typ.node.len, typ.base)
|
||||||
|
inc(elemCounter)
|
||||||
|
add result, "}"
|
||||||
|
|
||||||
|
proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
|
||||||
|
result = ""
|
||||||
|
reprSetAux(result, p, typ)
|
||||||
|
|
||||||
|
type
|
||||||
|
TReprClosure = record # we cannot use a global variable here
|
||||||
|
# as this wouldn't be thread-safe
|
||||||
|
marked: TCellSet
|
||||||
|
recdepth: int # do not recurse endless
|
||||||
|
indent: int # indentation
|
||||||
|
|
||||||
|
proc initReprClosure(cl: var TReprClosure) =
|
||||||
|
CellSetInit(cl.marked)
|
||||||
|
cl.recdepth = -1 # default is to display everything!
|
||||||
|
cl.indent = 0
|
||||||
|
|
||||||
|
proc deinitReprClosure(cl: var TReprClosure) =
|
||||||
|
CellSetDeinit(cl.marked)
|
||||||
|
|
||||||
|
proc reprBreak(result: var string, cl: TReprClosure) =
|
||||||
|
add result, "\n"
|
||||||
|
for i in 0..cl.indent-1: add result, ' '
|
||||||
|
|
||||||
|
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure)
|
||||||
|
|
||||||
|
proc reprArray(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
add result, "["
|
||||||
|
var bs = typ.base.size
|
||||||
|
for i in 0..typ.size div bs - 1:
|
||||||
|
if i > 0: add result, ", "
|
||||||
|
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
|
||||||
|
add result, "]"
|
||||||
|
|
||||||
|
proc reprSequence(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
if p == nil:
|
||||||
|
add result, "nil"
|
||||||
|
return
|
||||||
|
result.add(reprPointer(p) & "[")
|
||||||
|
var bs = typ.base.size
|
||||||
|
for i in 0..cast[PGenericSeq](p).len-1:
|
||||||
|
if i > 0: add result, ", "
|
||||||
|
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
|
||||||
|
typ.Base, cl)
|
||||||
|
add result, "]"
|
||||||
|
|
||||||
|
|
||||||
|
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
case n.kind
|
||||||
|
of nkNone: assert(false)
|
||||||
|
of nkSlot:
|
||||||
|
add result, $n.name
|
||||||
|
add result, " = "
|
||||||
|
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
|
||||||
|
of nkList:
|
||||||
|
for i in 0..n.len-1:
|
||||||
|
if i > 0: add result, ",\n"
|
||||||
|
reprRecordAux(result, p, n.sons[i], cl)
|
||||||
|
of nkCase:
|
||||||
|
var m = selectBranch(p, n)
|
||||||
|
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
|
||||||
|
if m != nil: reprRecordAux(result, p, m, cl)
|
||||||
|
|
||||||
|
proc reprRecord(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
add result, "["
|
||||||
|
reprRecordAux(result, p, typ.node, cl)
|
||||||
|
add result, "]"
|
||||||
|
|
||||||
|
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
# we know that p is not nil here:
|
||||||
|
var cell = usrToCell(p)
|
||||||
|
add result, "ref " & reprPointer(p)
|
||||||
|
if cell notin cl.marked:
|
||||||
|
# only the address is shown:
|
||||||
|
incl(cl.marked, cell)
|
||||||
|
add result, " --> "
|
||||||
|
reprAux(result, p, typ.base, cl)
|
||||||
|
|
||||||
|
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||||
|
cl: var TReprClosure) =
|
||||||
|
if cl.recdepth == 0:
|
||||||
|
add result, "..."
|
||||||
|
return
|
||||||
|
dec(cl.recdepth)
|
||||||
|
case typ.kind
|
||||||
|
of tySet: reprSetAux(result, p, typ)
|
||||||
|
of tyArray: reprArray(result, p, typ, cl)
|
||||||
|
of tyRecord: reprRecord(result, p, typ, cl)
|
||||||
|
of tyObject: # result = reprRecord(p, typ, cl)
|
||||||
|
var t = cast[ptr PNimType](p)^
|
||||||
|
reprRecord(result, p, t, cl)
|
||||||
|
of tyRef, tyPtr:
|
||||||
|
assert(p != nil)
|
||||||
|
if cast[ppointer](p)^ == nil: add result, "nil"
|
||||||
|
else: reprRef(result, cast[ppointer](p)^, typ, cl)
|
||||||
|
of tySequence:
|
||||||
|
reprSequence(result, cast[ppointer](p)^, typ, cl)
|
||||||
|
of tyInt: add result, $(cast[ptr int](p)^)
|
||||||
|
of tyInt8: add result, $int(cast[ptr Int8](p)^)
|
||||||
|
of tyInt16: add result, $int(cast[ptr Int16](p)^)
|
||||||
|
of tyInt32: add result, $int(cast[ptr Int32](p)^)
|
||||||
|
of tyInt64: add result, $(cast[ptr Int64](p)^)
|
||||||
|
of tyFloat: add result, $(cast[ptr float](p)^)
|
||||||
|
of tyFloat32: add result, $(cast[ptr float32](p)^)
|
||||||
|
of tyFloat64: add result, $(cast[ptr float64](p)^)
|
||||||
|
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
|
||||||
|
of tyBool: add result, reprBool(cast[ptr bool](p)^)
|
||||||
|
of tyChar: add result, reprChar(cast[ptr char](p)^)
|
||||||
|
of tyString: reprStrAux(result, cast[ptr string](p)^)
|
||||||
|
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
|
||||||
|
of tyRange: reprAux(result, p, typ.base, cl)
|
||||||
|
of tyProc, tyPointer:
|
||||||
|
if cast[ppointer](p)^ == nil: add result, "nil"
|
||||||
|
else: add result, reprPointer(cast[ppointer](p)^)
|
||||||
|
else:
|
||||||
|
add result, "(invalid data!)"
|
||||||
|
inc(cl.recdepth)
|
||||||
|
|
||||||
|
proc reprAny(p: pointer, typ: PNimType): string =
|
||||||
|
var
|
||||||
|
cl: TReprClosure
|
||||||
|
initReprClosure(cl)
|
||||||
|
result = ""
|
||||||
|
if typ.kind in {tyObject, tyRecord, tyArray, tySet}:
|
||||||
|
reprAux(result, p, typ, cl)
|
||||||
|
else:
|
||||||
|
reprAux(result, addr(p), typ, cl)
|
||||||
|
add result, "\n"
|
||||||
|
deinitReprClosure(cl)
|
||||||
88
lib/sets.nim
Executable file
88
lib/sets.nim
Executable file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# set handling
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyByte = int8
|
||||||
|
TNimSet = array [0..4*2048-1, TMyByte]
|
||||||
|
|
||||||
|
# implementation:
|
||||||
|
|
||||||
|
proc countBits(n: int32): int {.exportc: "countBits".}
|
||||||
|
# We use a prototype here, not in "cntbits.nim", because that is included
|
||||||
|
# in math.nim too. So when linking with math.nim it'd give a duplicated
|
||||||
|
# symbol error which we avoid by renaming here.
|
||||||
|
|
||||||
|
include cntbits
|
||||||
|
|
||||||
|
proc unionSets(res: var TNimSet, a, b: TNimSet, len: int) {.
|
||||||
|
compilerproc, inline.} =
|
||||||
|
for i in countup(0, len-1): res[i] = toU8(ze(a[i]) or ze(b[i]))
|
||||||
|
|
||||||
|
proc diffSets(res: var TNimSet, a, b: TNimSet, len: int) {.
|
||||||
|
compilerproc, inline.} =
|
||||||
|
for i in countup(0, len-1): res[i] = toU8(ze(a[i]) and not ze(b[i]))
|
||||||
|
|
||||||
|
proc intersectSets(res: var TNimSet, a, b: TNimSet, len: int) {.
|
||||||
|
compilerproc, inline.} =
|
||||||
|
for i in countup(0, len-1): res[i] = toU8(ze(a[i]) and ze(b[i]))
|
||||||
|
|
||||||
|
proc symdiffSets(res: var TNimSet, a, b: TNimSet, len: int) {.
|
||||||
|
compilerproc, inline.} =
|
||||||
|
for i in countup(0, len-1): res[i] = toU8(ze(a[i]) xor ze(b[i]))
|
||||||
|
|
||||||
|
proc containsSets(a, b: TNimSet, len: int): bool {.compilerproc, inline.} =
|
||||||
|
# s1 <= s2 ?
|
||||||
|
for i in countup(0, len-1):
|
||||||
|
if (ze(a[i]) and not ze(b[i])) != 0: return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc containsSubsets(a, b: TNimSet, len: int): bool {.compilerproc, inline.} =
|
||||||
|
# s1 < s2 ?
|
||||||
|
result = false # assume they are equal
|
||||||
|
for i in countup(0, len-1):
|
||||||
|
if (ze(a[i]) and not ze(b[i])) != 0: return false
|
||||||
|
if ze(a[i]) != ze(b[i]): result = true # they are not equal
|
||||||
|
|
||||||
|
proc equalSets(a, b: TNimSet, len: int): bool {.compilerproc, inline.} =
|
||||||
|
for i in countup(0, len-1):
|
||||||
|
if ze(a[i]) != ze(b[i]): return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc cardSet(s: TNimSet, len: int): int {.compilerproc, inline.} =
|
||||||
|
result = 0
|
||||||
|
for i in countup(0, len-1):
|
||||||
|
inc(result, countBits(ze(s[i])))
|
||||||
|
|
||||||
|
const
|
||||||
|
WORD_SIZE = sizeof(TMyByte)*8
|
||||||
|
|
||||||
|
proc inSet(s: TNimSet, elem: int): bool {.compilerproc, inline.} =
|
||||||
|
return (s[elem /% WORD_SIZE] and (1 shl (elem %% WORD_SIZE))) != 0
|
||||||
|
|
||||||
|
proc inclSets(s: var TNimSet, e: int) {.compilerproc, inline.} =
|
||||||
|
s[e /% WORD_SIZE] = toU8(s[e /% WORD_SIZE] or (1 shl (e %% WORD_SIZE)))
|
||||||
|
|
||||||
|
proc inclRange(s: var TNimSet, first, last: int) {.compilerproc.} =
|
||||||
|
# not very fast, but it is seldom used
|
||||||
|
for i in countup(first, last): inclSets(s, i)
|
||||||
|
|
||||||
|
proc smallInclRange(s: var int, first, last: int) {.compilerproc.} =
|
||||||
|
# not very fast, but it is seldom used
|
||||||
|
for i in countup(first, last):
|
||||||
|
s = s or (1 shl (i %% sizeof(int)*8))
|
||||||
|
|
||||||
|
proc exclSets(s: var TNimSet, e: int) {.compilerproc, inline.} =
|
||||||
|
s[e /% WORD_SIZE] = toU8(s[e /% WORD_SIZE] and
|
||||||
|
not (1 shl (e %% WORD_SIZE)))
|
||||||
|
|
||||||
|
proc smallContainsSubsets(a, b: int): bool {.compilerProc, inline.} =
|
||||||
|
# not used by new code generator
|
||||||
|
return ((a and not b) != 0) and (a != b)
|
||||||
627
lib/strutils.nim
Executable file
627
lib/strutils.nim
Executable file
|
|
@ -0,0 +1,627 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## This module contains various string utility routines.
|
||||||
|
## See the module `regexprs` for regular expression support.
|
||||||
|
|
||||||
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
# copied from excpt.nim, because I don't want to make this template public
|
||||||
|
template newException(exceptn, message: expr): expr =
|
||||||
|
block: # open a new scope
|
||||||
|
var
|
||||||
|
e: ref exceptn
|
||||||
|
new(e)
|
||||||
|
e.msg = message
|
||||||
|
e
|
||||||
|
|
||||||
|
type
|
||||||
|
TCharSet* = set[char] # for compability for Nim
|
||||||
|
|
||||||
|
const
|
||||||
|
Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}
|
||||||
|
## All the characters that count as whitespace.
|
||||||
|
|
||||||
|
strStart* = 0 # this is only for bootstraping
|
||||||
|
# XXX: remove this someday
|
||||||
|
nl* = "\n" # this is only for bootstraping XXX: remove this somehow
|
||||||
|
|
||||||
|
proc strip*(s: string): string {.noSideEffect.}
|
||||||
|
## Strips leading and trailing whitespace from `s`.
|
||||||
|
|
||||||
|
proc toLower*(s: string): string {.noSideEffect.}
|
||||||
|
## Converts `s` into lower case. This works only for the letters A-Z.
|
||||||
|
## See `charsets.nativeToLower` for a version that is locale-dependant.
|
||||||
|
|
||||||
|
proc toLower*(c: Char): Char {.noSideEffect.}
|
||||||
|
## Converts `c` into lower case. This works only for the letters A-Z.
|
||||||
|
## See `charsets.nativeToLower()` for a version that is locale-dependant.
|
||||||
|
|
||||||
|
proc toUpper*(s: string): string {.noSideEffect.}
|
||||||
|
## Converts `s` into upper case. This works only for the letters a-z.
|
||||||
|
## See `charsets.nativeToUpper()` for a version that is locale-dependant.
|
||||||
|
|
||||||
|
proc toUpper*(c: Char): Char {.noSideEffect.}
|
||||||
|
## Converts `c` into upper case. This works only for the letters a-z.
|
||||||
|
## See `charsets.nativeToUpper()` for a version that is locale-dependant.
|
||||||
|
|
||||||
|
proc capitalize*(s: string): string {.noSideEffect.}
|
||||||
|
## Converts the first character of `s` into upper case.
|
||||||
|
## This works only for the letters a-z.
|
||||||
|
|
||||||
|
proc normalize*(s: string): string {.noSideEffect.}
|
||||||
|
## Normalizes the string `s`. That means to convert it to lower case and
|
||||||
|
## remove any '_'. This is needed for Nimrod identifiers for example.
|
||||||
|
|
||||||
|
proc findSubStr*(sub, s: string, start: int = 0): int {.noSideEffect.}
|
||||||
|
## Searches for `sub` in `s` starting at position `start`. Searching is
|
||||||
|
## case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||||
|
|
||||||
|
proc findSubStr*(sub: char, s: string, start: int = 0): int {.noSideEffect.}
|
||||||
|
## Searches for `sub` in `s` starting at position `start`. Searching is
|
||||||
|
## case-sensitive. If `sub` is not in `s`, -1 is returned.
|
||||||
|
|
||||||
|
proc replaceStr*(s, sub, by: string): string {.noSideEffect.}
|
||||||
|
## Replaces `sub` in `s` by the string `by`.
|
||||||
|
|
||||||
|
proc deleteStr*(s: var string, first, last: int)
|
||||||
|
## Deletes in `s` the characters at position `first`..`last`. This modifies
|
||||||
|
## `s` itself, it does not return a copy.
|
||||||
|
|
||||||
|
proc toOctal*(c: char): string
|
||||||
|
## Converts a character `c` to its octal representation. The resulting
|
||||||
|
## string may not have a leading zero. Its length is always exactly 3.
|
||||||
|
|
||||||
|
iterator split*(s: string, seps: set[char] = Whitespace): string =
|
||||||
|
## Splits the string `s` into substrings.
|
||||||
|
##
|
||||||
|
## Substrings are separated by a substring containing only `seps`.
|
||||||
|
## The seperator substrings are not returned in `sub`, nor are they part
|
||||||
|
## of `sub`.
|
||||||
|
## Examples::
|
||||||
|
##
|
||||||
|
## for word in split(" this is an example "):
|
||||||
|
## writeln(stdout, word)
|
||||||
|
##
|
||||||
|
## Results in::
|
||||||
|
##
|
||||||
|
## "this"
|
||||||
|
## "is"
|
||||||
|
## "an"
|
||||||
|
## "example"
|
||||||
|
##
|
||||||
|
## for word in split(";;this;is;an;;example;;;", {';'}):
|
||||||
|
## writeln(stdout, word)
|
||||||
|
##
|
||||||
|
## produces in the same output.
|
||||||
|
var
|
||||||
|
first: int = 0
|
||||||
|
last: int = 0
|
||||||
|
assert(not ('\0' in seps))
|
||||||
|
while last < len(s):
|
||||||
|
while s[last] in seps: inc(last)
|
||||||
|
first = last
|
||||||
|
while last < len(s) and s[last] not_in seps: inc(last) # BUGFIX!
|
||||||
|
yield copy(s, first, last-1)
|
||||||
|
|
||||||
|
proc splitSeq*(s: string, seps: set[char] = Whitespace): seq[string] {.
|
||||||
|
noSideEffect.}
|
||||||
|
## The same as `split`, but is a proc that returns a sequence of substrings.
|
||||||
|
|
||||||
|
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect.}
|
||||||
|
## Compares two strings in a case insensitive manner. Returns:
|
||||||
|
##
|
||||||
|
## | 0 iff a == b
|
||||||
|
## | < 0 iff a < b
|
||||||
|
## | > 0 iff a > b
|
||||||
|
|
||||||
|
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect.}
|
||||||
|
## Compares two strings normalized (i.e. case and
|
||||||
|
## underscores do not matter). Returns:
|
||||||
|
##
|
||||||
|
## | 0 iff a == b
|
||||||
|
## | < 0 iff a < b
|
||||||
|
## | > 0 iff a > b
|
||||||
|
|
||||||
|
proc in_Operator*(s: string, c: char): bool {.noSideEffect.}
|
||||||
|
## Same as `findSubStr(c, s) >= 0`.
|
||||||
|
|
||||||
|
proc in_Operator*(s, sub: string): bool {.noSideEffect.}
|
||||||
|
## Same as `findSubStr(sub, s) >= 0`.
|
||||||
|
|
||||||
|
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect.}
|
||||||
|
## Converts `x` to its hexadecimal representation. The resulting string
|
||||||
|
## will be exactly `len` characters long. No prefix like ``0x``
|
||||||
|
## is generated. `x` is treated as unsigned value.
|
||||||
|
|
||||||
|
proc intToStr*(x: int, minchars: int = 1): string
|
||||||
|
## Converts `x` to its decimal representation. The resulting string
|
||||||
|
## will be minimally `minchars` characters long. This is achieved by
|
||||||
|
## adding leading zeros.
|
||||||
|
|
||||||
|
proc ParseInt*(s: string): int {.noSideEffect.}
|
||||||
|
## Parses a decimal integer value contained in `s`. If `s` is not
|
||||||
|
## a valid integer, `EInvalidValue` is raised.
|
||||||
|
# XXX: make this biggestint!
|
||||||
|
|
||||||
|
proc ParseFloat*(s: string): float {.noSideEffect.}
|
||||||
|
## Parses a decimal floating point value contained in `s`. If `s` is not
|
||||||
|
## a valid floating point number, `EInvalidValue` is raised.
|
||||||
|
# XXX: make this biggestfloat.
|
||||||
|
|
||||||
|
# the stringify and format operators:
|
||||||
|
proc toString*[Ty](x: Ty): string
|
||||||
|
## This generic proc is the same as the stringify operator `$`.
|
||||||
|
|
||||||
|
proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
|
||||||
|
## The substitution operator performs string substitutions in `formatstr`
|
||||||
|
## and returns the modified `formatstr`.
|
||||||
|
##
|
||||||
|
## This is best explained by an example::
|
||||||
|
##
|
||||||
|
## "$1 eats $2." % ["The cat", "fish"]
|
||||||
|
##
|
||||||
|
## Results in::
|
||||||
|
##
|
||||||
|
## "The cat eats fish."
|
||||||
|
##
|
||||||
|
## The substitution variables (the thing after the ``$``)
|
||||||
|
## are enumerated from 1 to 9.
|
||||||
|
## Substitution variables can also be words (that is
|
||||||
|
## ``[A-Za-z_]+[A-Za-z0-9_]*``) in which case the arguments in `a` with even
|
||||||
|
## indices are keys and with odd indices are the corresponding values. Again
|
||||||
|
## an example::
|
||||||
|
##
|
||||||
|
## "$animal eats $food." % ["animal", "The cat", "food", "fish"]
|
||||||
|
##
|
||||||
|
## Results in::
|
||||||
|
##
|
||||||
|
## "The cat eats fish."
|
||||||
|
##
|
||||||
|
## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is
|
||||||
|
## raised if an ill-formed format string has been passed to the `%` operator.
|
||||||
|
|
||||||
|
proc `%` *(formatstr, a: string): string {.noSideEffect.}
|
||||||
|
## This is the same as `formatstr % [a]`.
|
||||||
|
|
||||||
|
proc repeatChar*(count: int, c: Char = ' '): string
|
||||||
|
## Returns a string of length `count` consisting only of
|
||||||
|
## the character `c`.
|
||||||
|
|
||||||
|
proc startsWith*(s, prefix: string): bool {.noSideEffect.}
|
||||||
|
## Returns true iff ``s`` starts with ``prefix``.
|
||||||
|
## If ``prefix == ""`` true is returned.
|
||||||
|
|
||||||
|
proc endsWith*(s, suffix: string): bool {.noSideEffect.}
|
||||||
|
## Returns true iff ``s`` ends with ``suffix``.
|
||||||
|
## If ``suffix == ""`` true is returned.
|
||||||
|
|
||||||
|
# implementation
|
||||||
|
|
||||||
|
proc allCharsInSet*(s: string, theSet: TCharSet): bool =
|
||||||
|
## returns true iff each character of `s` is in the set `theSet`.
|
||||||
|
for c in items(s):
|
||||||
|
if not (c in theSet): return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc c_strcmp(a, b: CString): int {.importc: "strcmp", nodecl.}
|
||||||
|
|
||||||
|
proc startsWith(s, prefix: string): bool =
|
||||||
|
var i = 0
|
||||||
|
while true:
|
||||||
|
if prefix[i] == '\0': return true
|
||||||
|
if s[i] != prefix[i]: return false
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
proc endsWith(s, suffix: string): bool =
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
j = len(s) - len(suffix)
|
||||||
|
while true:
|
||||||
|
if suffix[i] == '\0': return true
|
||||||
|
if s[i+j] != suffix[i]: return false
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
proc repeatChar(count: int, c: Char = ' '): string =
|
||||||
|
result = newString(count)
|
||||||
|
for i in 0..count-1:
|
||||||
|
result[i] = c
|
||||||
|
|
||||||
|
proc intToStr(x: int, minchars: int = 1): string =
|
||||||
|
result = $abs(x)
|
||||||
|
for i in 1 .. minchars - len(result):
|
||||||
|
result = '0' & result
|
||||||
|
if x < 0:
|
||||||
|
result = '-' & result
|
||||||
|
|
||||||
|
proc toString[Ty](x: Ty): string = return $x
|
||||||
|
|
||||||
|
proc toOctal(c: char): string =
|
||||||
|
var
|
||||||
|
val: int
|
||||||
|
result = newString(3)
|
||||||
|
val = ord(c)
|
||||||
|
for i in countdown(2, 0):
|
||||||
|
result[i] = Chr(val mod 8 + ord('0'))
|
||||||
|
val = val div 8
|
||||||
|
|
||||||
|
proc `%`(formatstr: string, a: string): string =
|
||||||
|
return formatstr % [a]
|
||||||
|
|
||||||
|
proc findNormalized(x: string, inArray: openarray[string]): int =
|
||||||
|
var i = 0
|
||||||
|
while i < high(inArray):
|
||||||
|
if cmpIgnoreStyle(x, inArray[i]) == 0: return i
|
||||||
|
inc(i, 2) # incrementing by 1 would probably result in a
|
||||||
|
# security whole ...
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc `%`(formatstr: string, a: openarray[string]): string =
|
||||||
|
# the format operator
|
||||||
|
const
|
||||||
|
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
|
||||||
|
result = ""
|
||||||
|
var i = 0
|
||||||
|
while i < len(formatstr):
|
||||||
|
if formatstr[i] == '$':
|
||||||
|
case formatstr[i+1] # again we use the fact that strings
|
||||||
|
# are zero-terminated here
|
||||||
|
of '$':
|
||||||
|
add result, '$'
|
||||||
|
inc(i, 2)
|
||||||
|
of '1'..'9':
|
||||||
|
var j = 0
|
||||||
|
inc(i) # skip $
|
||||||
|
while formatstr[i] in {'0'..'9'}:
|
||||||
|
j = j * 10 + ord(formatstr[i]) - ord('0')
|
||||||
|
inc(i)
|
||||||
|
add result, a[j - 1]
|
||||||
|
of '{':
|
||||||
|
var j = i+1
|
||||||
|
while formatstr[j] notin {'\0', '}'}: inc(j)
|
||||||
|
var x = findNormalized(copy(formatstr, i+2, j-1), a)
|
||||||
|
if x >= 0 and x < high(a): add result, a[x+1]
|
||||||
|
else: raise newException(EInvalidValue, "invalid format string")
|
||||||
|
i = j+1
|
||||||
|
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
|
||||||
|
var j = i+1
|
||||||
|
while formatstr[j] in PatternChars: inc(j)
|
||||||
|
var x = findNormalized(copy(formatstr, i+1, j-1), a)
|
||||||
|
if x >= 0 and x < high(a): add result, a[x+1]
|
||||||
|
else: raise newException(EInvalidValue, "invalid format string")
|
||||||
|
i = j
|
||||||
|
else: raise newException(EInvalidValue, "invalid format string")
|
||||||
|
else:
|
||||||
|
add result, formatstr[i]
|
||||||
|
inc(i)
|
||||||
|
|
||||||
|
proc cmpIgnoreCase(a, b: string): int =
|
||||||
|
# makes usage of the fact that strings are zero-terminated
|
||||||
|
var
|
||||||
|
aa, bb: char
|
||||||
|
for i in 0..len(a)-1:
|
||||||
|
aa = toLower(a[i])
|
||||||
|
bb = toLower(b[i])
|
||||||
|
result = ord(aa) - ord(bb)
|
||||||
|
if result != 0: break
|
||||||
|
|
||||||
|
{.push checks: off, line_trace: off .} # this is a hot-spot in the compiler!
|
||||||
|
# thus we compile without checks here
|
||||||
|
|
||||||
|
proc cmpIgnoreStyle(a, b: string): int =
|
||||||
|
var
|
||||||
|
aa, bb: char
|
||||||
|
i = 0
|
||||||
|
j = 0
|
||||||
|
while True:
|
||||||
|
while a[i] == '_': inc(i)
|
||||||
|
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||||
|
aa = toLower(a[i])
|
||||||
|
bb = toLower(b[j])
|
||||||
|
result = ord(aa) - ord(bb)
|
||||||
|
if result != 0 or aa == '\0': break
|
||||||
|
inc(i)
|
||||||
|
inc(j)
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
# ---------- splitting -----------------------------------------------------
|
||||||
|
|
||||||
|
proc splitSeq(s: string, seps: set[char]): seq[string] =
|
||||||
|
result = []
|
||||||
|
for sub in split(s, seps): add result, sub
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc strip(s: string): string =
|
||||||
|
const
|
||||||
|
chars: set[Char] = Whitespace
|
||||||
|
var
|
||||||
|
first = 0
|
||||||
|
last = len(s)-1
|
||||||
|
while s[first] in chars: inc(first)
|
||||||
|
while last >= 0 and s[last] in chars: dec(last)
|
||||||
|
result = copy(s, first, last)
|
||||||
|
|
||||||
|
proc toLower(c: Char): Char =
|
||||||
|
if c in {'A'..'Z'}:
|
||||||
|
result = chr(ord(c) + (ord('a') - ord('A')))
|
||||||
|
else:
|
||||||
|
result = c
|
||||||
|
|
||||||
|
proc toLower(s: string): string =
|
||||||
|
result = newString(len(s))
|
||||||
|
for i in 0..len(s) - 1:
|
||||||
|
result[i] = toLower(s[i])
|
||||||
|
|
||||||
|
proc toUpper(c: Char): Char =
|
||||||
|
if c in {'a'..'z'}:
|
||||||
|
result = Chr(Ord(c) - (Ord('a') - Ord('A')))
|
||||||
|
else:
|
||||||
|
result = c
|
||||||
|
|
||||||
|
proc toUpper(s: string): string =
|
||||||
|
result = newString(len(s))
|
||||||
|
for i in 0..len(s) - 1:
|
||||||
|
result[i] = toUpper(s[i])
|
||||||
|
|
||||||
|
proc capitalize(s: string): string =
|
||||||
|
result = toUpper(s[0]) & copy(s, 1)
|
||||||
|
|
||||||
|
proc normalize(s: string): string =
|
||||||
|
result = ""
|
||||||
|
for i in 0..len(s) - 1:
|
||||||
|
if s[i] in {'A'..'Z'}:
|
||||||
|
add result, Chr(Ord(s[i]) + (Ord('a') - Ord('A')))
|
||||||
|
elif s[i] != '_':
|
||||||
|
add result, s[i]
|
||||||
|
|
||||||
|
type
|
||||||
|
TSkipTable = array[Char, int]
|
||||||
|
|
||||||
|
proc preprocessSub(sub: string, a: var TSkipTable) =
|
||||||
|
var m = len(sub)
|
||||||
|
for i in 0..0xff: a[chr(i)] = m+1
|
||||||
|
for i in 0..m-1: a[sub[i]] = m-i
|
||||||
|
|
||||||
|
proc findSubStrAux(sub, s: string, start: int, a: TSkipTable): int =
|
||||||
|
# fast "quick search" algorithm:
|
||||||
|
var
|
||||||
|
m = len(sub)
|
||||||
|
n = len(s)
|
||||||
|
# search:
|
||||||
|
var j = start
|
||||||
|
while j <= n - m:
|
||||||
|
block match:
|
||||||
|
for k in 0..m-1:
|
||||||
|
if sub[k] != s[k+j]: break match
|
||||||
|
return j
|
||||||
|
inc(j, a[s[j+m]])
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc findSubStr(sub, s: string, start: int = 0): int =
|
||||||
|
var a: TSkipTable
|
||||||
|
preprocessSub(sub, a)
|
||||||
|
result = findSubStrAux(sub, s, start, a)
|
||||||
|
# slow linear search:
|
||||||
|
#var
|
||||||
|
# i, j, M, N: int
|
||||||
|
#M = len(sub)
|
||||||
|
#N = len(s)
|
||||||
|
#i = start
|
||||||
|
#j = 0
|
||||||
|
#if i >= N:
|
||||||
|
# result = -1
|
||||||
|
#else:
|
||||||
|
# while True:
|
||||||
|
# if s[i] == sub[j]:
|
||||||
|
# Inc(i)
|
||||||
|
# Inc(j)
|
||||||
|
# else:
|
||||||
|
# i = i - j + 1
|
||||||
|
# j = 0
|
||||||
|
# if (j >= M):
|
||||||
|
# return i - M
|
||||||
|
# elif (i >= N):
|
||||||
|
# return -1
|
||||||
|
|
||||||
|
|
||||||
|
proc findSubStr(sub: char, s: string, start: int = 0): int =
|
||||||
|
for i in start..len(s)-1:
|
||||||
|
if sub == s[i]: return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
proc in_Operator(s: string, c: char): bool =
|
||||||
|
return findSubStr(c, s) >= 0
|
||||||
|
|
||||||
|
proc in_Operator(s, sub: string): bool =
|
||||||
|
return findSubStr(sub, s) >= 0
|
||||||
|
|
||||||
|
proc replaceStr(s, sub, by: string): string =
|
||||||
|
var
|
||||||
|
i, j: int
|
||||||
|
a: TSkipTable
|
||||||
|
result = ""
|
||||||
|
preprocessSub(sub, a)
|
||||||
|
i = 0
|
||||||
|
while true:
|
||||||
|
j = findSubStrAux(sub, s, i, a)
|
||||||
|
if j < 0: break
|
||||||
|
add result, copy(s, i, j - 1)
|
||||||
|
add result, by
|
||||||
|
i = j + len(sub)
|
||||||
|
# copy the rest:
|
||||||
|
add result, copy(s, i)
|
||||||
|
|
||||||
|
proc deleteStr(s: var string, first, last: int) =
|
||||||
|
# example: "abc___uvwxyz\0" (___ is to be deleted)
|
||||||
|
# --> first == 3, last == 5
|
||||||
|
# s[first..] = s[last+1..]
|
||||||
|
var
|
||||||
|
i = first
|
||||||
|
while last+i+1 < len(s):
|
||||||
|
s[i] = s[last+i+1]
|
||||||
|
inc(i)
|
||||||
|
setlen(s, len(s)-(last-first+1))
|
||||||
|
|
||||||
|
# parsing numbers:
|
||||||
|
|
||||||
|
proc sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.}
|
||||||
|
|
||||||
|
proc toHex(x: BiggestInt, len: int): string =
|
||||||
|
const
|
||||||
|
HexChars = "0123456789ABCDEF"
|
||||||
|
var
|
||||||
|
shift: BiggestInt
|
||||||
|
result = newString(len)
|
||||||
|
shift = 0
|
||||||
|
for j in countdown(len-1, 0):
|
||||||
|
result[j] = HexChars[toU32(x shr shift) and 0xF]
|
||||||
|
shift = shift + 4
|
||||||
|
|
||||||
|
{.push overflowChecks: on.}
|
||||||
|
# this must be compiled with overflow checking turned on:
|
||||||
|
proc rawParseInt(s: string, index: var int): BiggestInt =
|
||||||
|
# index contains the start position at proc entry; end position will be
|
||||||
|
# an index before the proc returns; index = -1 on error (no number at all)
|
||||||
|
# the problem here is that integers have an asymmetrical range: there is
|
||||||
|
# one more valid negative than prositive integer. Thus we perform the
|
||||||
|
# computation as a negative number and then change the sign at the end.
|
||||||
|
var
|
||||||
|
i: int
|
||||||
|
sign: BiggestInt
|
||||||
|
i = index
|
||||||
|
# a local i is more efficient than accessing an in out parameter
|
||||||
|
sign = -1
|
||||||
|
if s[i] == '+':
|
||||||
|
inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
inc(i)
|
||||||
|
sign = 1
|
||||||
|
if s[i] in {'0'..'9'}:
|
||||||
|
result = 0
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
result = result * 10 - (ord(s[i]) - ord('0'))
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_':
|
||||||
|
inc(i) # underscores are allowed and ignored
|
||||||
|
result = result * sign
|
||||||
|
index = i # store index back
|
||||||
|
else:
|
||||||
|
index = -1
|
||||||
|
|
||||||
|
{.pop.} # overflowChecks
|
||||||
|
|
||||||
|
proc parseInt(s: string): int =
|
||||||
|
var
|
||||||
|
index: int
|
||||||
|
res: BiggestInt
|
||||||
|
index = strStart
|
||||||
|
res = rawParseInt(s, index)
|
||||||
|
if index == -1:
|
||||||
|
raise newException(EInvalidValue, "invalid integer: " & s)
|
||||||
|
elif (sizeof(int) <= 4) and
|
||||||
|
((res < low(int)) or (res > high(int))):
|
||||||
|
raise newException(EOverflow, "overflow")
|
||||||
|
else:
|
||||||
|
result = int(res) # convert to smaller integer type
|
||||||
|
|
||||||
|
proc ParseFloat(s: string): float =
|
||||||
|
var
|
||||||
|
hd, esign, sign: float
|
||||||
|
exponent, i: int
|
||||||
|
flags: int
|
||||||
|
result = 0.0
|
||||||
|
i = 0
|
||||||
|
exponent = 0
|
||||||
|
esign = 1.0
|
||||||
|
flags = 0
|
||||||
|
sign = 1.0
|
||||||
|
if s[i] == '+': inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
sign = -1.0
|
||||||
|
inc(i)
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
# Read integer part
|
||||||
|
flags = flags or 1
|
||||||
|
result = result * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
# Decimal?
|
||||||
|
if s[i] == '.':
|
||||||
|
hd = 1.0
|
||||||
|
inc(i)
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
# Read fractional part
|
||||||
|
flags = flags or 2
|
||||||
|
result = result * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
||||||
|
hd = hd * 10.0
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
result = result / hd # this complicated way preserves precision
|
||||||
|
# Again, read integer and fractional part
|
||||||
|
if flags == 0:
|
||||||
|
raise newException(EInvalidValue, "invalid float:" & s)
|
||||||
|
# Exponent?
|
||||||
|
if s[i] in {'e', 'E'}:
|
||||||
|
inc(i)
|
||||||
|
if s[i] == '+':
|
||||||
|
inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
esign = -1.0
|
||||||
|
inc(i)
|
||||||
|
if s[i] notin {'0'..'9'}:
|
||||||
|
raise newException(EInvalidValue, "invalid float: " & s)
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
exponent = exponent * 10 + ord(s[i]) - ord('0')
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
# Calculate Exponent
|
||||||
|
hd = 1.0
|
||||||
|
for j in 1..exponent:
|
||||||
|
hd = hd * 10.0
|
||||||
|
if esign > 0.0: result = result * hd
|
||||||
|
else: result = result / hd
|
||||||
|
# Not all characters are read?
|
||||||
|
if s[i] != '\0': raise newException(EInvalidValue, "invalid float: " & s)
|
||||||
|
# evaluate sign
|
||||||
|
result = result * sign
|
||||||
|
|
||||||
|
proc toOct*(x: BiggestInt, len: int): string =
|
||||||
|
## converts `x` into its octal representation. The resulting string is
|
||||||
|
## always `len` characters long. No leading ``0c`` prefix is generated.
|
||||||
|
var
|
||||||
|
mask, shift: BiggestInt
|
||||||
|
assert(len > 0)
|
||||||
|
result = newString(len)
|
||||||
|
mask = 7
|
||||||
|
shift = 0
|
||||||
|
for j in countdown(len-1, 0):
|
||||||
|
result[j] = chr(int((x and mask) shr shift) + ord('0'))
|
||||||
|
shift = shift + 3
|
||||||
|
mask = mask shl 3
|
||||||
|
|
||||||
|
proc toBin*(x: BiggestInt, len: int): string =
|
||||||
|
## converts `x` into its binary representation. The resulting string is
|
||||||
|
## always `len` characters long. No leading ``0b`` prefix is generated.
|
||||||
|
var
|
||||||
|
mask, shift: BiggestInt
|
||||||
|
assert(len > 0)
|
||||||
|
result = newString(len)
|
||||||
|
mask = 1
|
||||||
|
shift = 0
|
||||||
|
for j in countdown(len-1, 0):
|
||||||
|
result[j] = chr(int((x and mask) shr shift) + ord('0'))
|
||||||
|
shift = shift + 1
|
||||||
|
mask = mask shl 1
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
163
lib/sysio.nim
Executable file
163
lib/sysio.nim
Executable file
|
|
@ -0,0 +1,163 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
## Nimrod's standard IO library. It contains high-performance
|
||||||
|
## routines for reading and writing data to (buffered) files or
|
||||||
|
## TTYs.
|
||||||
|
|
||||||
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
|
||||||
|
proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl.}
|
||||||
|
proc fgets(c: cstring, n: int, f: TFile): cstring {.importc: "fgets", noDecl.}
|
||||||
|
proc fgetc(stream: TFile): int {.importc: "fgetc", nodecl.}
|
||||||
|
proc ungetc(c: int, f: TFile) {.importc: "ungetc", nodecl.}
|
||||||
|
proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl.}
|
||||||
|
proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs.}
|
||||||
|
proc strlen(c: cstring): int {.importc: "strlen", nodecl.}
|
||||||
|
|
||||||
|
proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
|
||||||
|
importc, nodecl.}
|
||||||
|
|
||||||
|
proc write(f: TFile, c: cstring) = fputs(c, f)
|
||||||
|
|
||||||
|
var
|
||||||
|
IOFBF {.importc: "_IOFBF", nodecl.}: cint
|
||||||
|
IONBF {.importc: "_IONBF", nodecl.}: cint
|
||||||
|
|
||||||
|
# copied here to remove dependancy on strutils:
|
||||||
|
#proc toNimstr(x: Cstring, len: int): string {.
|
||||||
|
# noSideEffect, importc: "toNimStr".}
|
||||||
|
|
||||||
|
proc rawReadLine(f: TFile, result: var string) {.noStatic.} =
|
||||||
|
# of course this could be optimized a bit; but IO is slow anyway...
|
||||||
|
# and it was difficult to get this CORRECT with Ansi C's methods
|
||||||
|
var
|
||||||
|
c: cint
|
||||||
|
setLen(result, 0) # reuse the buffer!
|
||||||
|
while True:
|
||||||
|
c = fgetc(f)
|
||||||
|
if c < 0:
|
||||||
|
result = nil
|
||||||
|
break # EOF
|
||||||
|
if c == 10: break # LF
|
||||||
|
if c == 13: # CR
|
||||||
|
c = fgetc(f) # is the next char LF?
|
||||||
|
if c != 10: ungetc(c, f) # no, put the character back
|
||||||
|
break
|
||||||
|
add result, chr(int(c))
|
||||||
|
|
||||||
|
proc readLine(f: TFile): string =
|
||||||
|
result = ""
|
||||||
|
rawReadLine(f, result)
|
||||||
|
|
||||||
|
proc readFile(filename: string): string =
|
||||||
|
var f: TFile
|
||||||
|
try:
|
||||||
|
if openFile(f, filename):
|
||||||
|
var len = getFileSize(f)
|
||||||
|
if len < high(int):
|
||||||
|
result = newString(int(len))
|
||||||
|
if readBuffer(f, addr(result[0]), int(len)) != len:
|
||||||
|
result = nil
|
||||||
|
closeFile(f)
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
except EIO:
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
proc write(f: TFile, s: string) = fputs(s, f)
|
||||||
|
proc write(f: TFile, i: int) = fprintf(f, "%ld", i)
|
||||||
|
proc write(f: TFile, b: bool) =
|
||||||
|
if b: write(f, "true")
|
||||||
|
else: write(f, "false")
|
||||||
|
proc write(f: TFile, r: float) = fprintf(f, "%g", r)
|
||||||
|
proc write(f: TFile, c: Char) = putc(c, f)
|
||||||
|
|
||||||
|
proc EndOfFile(f: TFile): bool =
|
||||||
|
# do not blame me; blame the ANSI C standard this is so brain-damaged
|
||||||
|
var
|
||||||
|
c: int
|
||||||
|
c = fgetc(f)
|
||||||
|
ungetc(c, f)
|
||||||
|
return c == -1
|
||||||
|
|
||||||
|
proc writeln[Ty](f: TFile, x: Ty) =
|
||||||
|
write(f, x)
|
||||||
|
write(f, "\n")
|
||||||
|
proc echo[Ty](x: Ty) = writeln(stdout, x)
|
||||||
|
|
||||||
|
# interface to the C procs:
|
||||||
|
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
|
||||||
|
|
||||||
|
const
|
||||||
|
FormatOpen: array [TFileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"]
|
||||||
|
#"rt", "wt", "w+t", "r+t", "at"
|
||||||
|
# we always use binary here as for Nimrod the OS line ending
|
||||||
|
# should not be translated.
|
||||||
|
|
||||||
|
|
||||||
|
proc OpenFile(f: var TFile, filename: string,
|
||||||
|
mode: TFileMode = fmRead,
|
||||||
|
bufSize: int = -1): Bool =
|
||||||
|
var
|
||||||
|
p: pointer
|
||||||
|
p = fopen(filename, FormatOpen[mode])
|
||||||
|
result = (p != nil)
|
||||||
|
f = cast[TFile](p)
|
||||||
|
if bufSize > 0:
|
||||||
|
if setvbuf(f, nil, IOFBF, bufSize) != 0:
|
||||||
|
raise newException(EOutOfMemory, "out of memory")
|
||||||
|
elif bufSize == 0:
|
||||||
|
discard setvbuf(f, nil, IONBF, 0)
|
||||||
|
|
||||||
|
# C routine that is used here:
|
||||||
|
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
|
||||||
|
importc: "fread", noDecl.}
|
||||||
|
proc fseek(f: TFile, offset: clong, whence: int): int {.
|
||||||
|
importc: "fseek", noDecl.}
|
||||||
|
proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
|
||||||
|
|
||||||
|
proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
|
||||||
|
importc: "fwrite", noDecl.}
|
||||||
|
# size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
|
||||||
|
|
||||||
|
proc readBuffer(f: TFile, buffer: pointer, len: int): int =
|
||||||
|
result = fread(buffer, 1, len, f)
|
||||||
|
|
||||||
|
proc ReadBytes(f: TFile, a: var openarray[byte], start, len: int): int =
|
||||||
|
result = readBuffer(f, addr(a[start]), len)
|
||||||
|
|
||||||
|
proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int =
|
||||||
|
result = readBuffer(f, addr(a[start]), len)
|
||||||
|
|
||||||
|
proc writeBytes(f: TFile, a: openarray[byte], start, len: int): int =
|
||||||
|
result = writeBuffer(f, addr(a[start]), len)
|
||||||
|
proc writeChars(f: TFile, a: openarray[char], start, len: int): int =
|
||||||
|
result = writeBuffer(f, addr(a[start]), len)
|
||||||
|
proc writeBuffer(f: TFile, buffer: pointer, len: int): int =
|
||||||
|
result = fwrite(buffer, 1, len, f)
|
||||||
|
|
||||||
|
proc setFilePos(f: TFile, pos: int64) =
|
||||||
|
if fseek(f, clong(pos), 0) != 0:
|
||||||
|
raise newException(EIO, "cannot set file position")
|
||||||
|
|
||||||
|
proc getFilePos(f: TFile): int64 =
|
||||||
|
result = ftell(f)
|
||||||
|
if result < 0: raise newException(EIO, "cannot retrieve file position")
|
||||||
|
|
||||||
|
proc getFileSize(f: TFile): int64 =
|
||||||
|
var oldPos = getFilePos(f)
|
||||||
|
discard fseek(f, 0, 2) # seek the end of the file
|
||||||
|
result = getFilePos(f)
|
||||||
|
setFilePos(f, oldPos)
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
294
lib/sysstr.nim
Executable file
294
lib/sysstr.nim
Executable file
|
|
@ -0,0 +1,294 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# string & sequence handling procedures needed by the code generator
|
||||||
|
|
||||||
|
# strings are dynamically resized, have a length field
|
||||||
|
# and are zero-terminated, so they can be casted to C
|
||||||
|
# strings easily
|
||||||
|
# we don't use refcounts because that's a behaviour
|
||||||
|
# the programmer may not want
|
||||||
|
|
||||||
|
type
|
||||||
|
TStringDesc {.importc, nodecl.} = record
|
||||||
|
len, space: int # len and space without counting the terminating zero
|
||||||
|
data: array[0..0, char] # for the '\0' character
|
||||||
|
|
||||||
|
mstring {.importc: "string".} = ptr TStringDesc
|
||||||
|
|
||||||
|
# implementation:
|
||||||
|
|
||||||
|
proc resize(old: int): int {.inline.} =
|
||||||
|
assert(old < 65536 * 4)
|
||||||
|
if old <= 0: return 1
|
||||||
|
elif old < 65536: return old * 2
|
||||||
|
else: return old * 3 div 2 # for large arrays * 3/2 is better
|
||||||
|
|
||||||
|
proc cmpStrings(a, b: mstring): int {.inline, compilerProc.} =
|
||||||
|
if a == b: return 0
|
||||||
|
if a == nil: return -1
|
||||||
|
if b == nil: return 1
|
||||||
|
return c_strcmp(a.data, b.data)
|
||||||
|
|
||||||
|
proc eqStrings(a, b: mstring): bool {.inline, compilerProc.} =
|
||||||
|
if a == b: return true
|
||||||
|
if a == nil or b == nil: return false
|
||||||
|
return a.len == b.len and
|
||||||
|
c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0
|
||||||
|
|
||||||
|
proc rawNewString(space: int): mstring {.compilerProc.} =
|
||||||
|
result = cast[mstring](newObj(addr(strDesc), sizeof(TStringDesc) +
|
||||||
|
space * sizeof(char)))
|
||||||
|
result.len = 0
|
||||||
|
result.space = space
|
||||||
|
result.data[0] = '\0'
|
||||||
|
|
||||||
|
proc mnewString(len: int): mstring {.exportc.} =
|
||||||
|
result = rawNewString(len)
|
||||||
|
result.len = len
|
||||||
|
result.data[len] = '\0'
|
||||||
|
|
||||||
|
proc toNimStr(str: CString, len: int): mstring {.compilerProc.} =
|
||||||
|
result = rawNewString(len)
|
||||||
|
result.len = len
|
||||||
|
c_memcpy(result.data, str, (len+1) * sizeof(Char))
|
||||||
|
result.data[len] = '\0' # IO.readline relies on this!
|
||||||
|
|
||||||
|
proc cstrToNimstr(str: CString): mstring {.compilerProc.} =
|
||||||
|
return toNimstr(str, c_strlen(str))
|
||||||
|
|
||||||
|
proc copyString(src: mstring): mstring {.compilerProc.} =
|
||||||
|
result = rawNewString(src.space)
|
||||||
|
result.len = src.len
|
||||||
|
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char))
|
||||||
|
|
||||||
|
proc hashString(s: string): int {.compilerproc.} =
|
||||||
|
# the compiler needs exactly the same hash function!
|
||||||
|
# this used to be used for efficient generation of string case statements
|
||||||
|
var
|
||||||
|
h: int
|
||||||
|
h = 0
|
||||||
|
for i in 0..Len(s)-1:
|
||||||
|
h = h +% Ord(s[i])
|
||||||
|
h = h +% h shl 10
|
||||||
|
h = h xor (h shr 6)
|
||||||
|
h = h +% h shl 3
|
||||||
|
h = h xor (h shr 11)
|
||||||
|
h = h +% h shl 15
|
||||||
|
result = h
|
||||||
|
|
||||||
|
# copy(s: string, start = 0): string
|
||||||
|
# {.extern: "copyStr", noDecl, noSideEffect.}
|
||||||
|
# copy(s: string, start, len: int): string
|
||||||
|
# {.extern: "copyStrLen", noDecl, noSideEffect.}
|
||||||
|
#
|
||||||
|
# setLength(var s: string, newlen: int)
|
||||||
|
# {.extern: "setLengthStr", noDecl, noSideEffect.}
|
||||||
|
|
||||||
|
|
||||||
|
proc copyStrLast(s: mstring, start, last: int): mstring {.exportc.} =
|
||||||
|
var
|
||||||
|
len: int
|
||||||
|
if start >= s.len: return mnewString(0) # BUGFIX
|
||||||
|
if last >= s.len:
|
||||||
|
len = s.len - start # - 1 + 1
|
||||||
|
else:
|
||||||
|
len = last - start + 1
|
||||||
|
result = rawNewString(len)
|
||||||
|
result.len = len
|
||||||
|
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
|
||||||
|
result.data[len] = '\0'
|
||||||
|
|
||||||
|
proc copyStr(s: mstring, start: int): mstring {.exportc.} =
|
||||||
|
return copyStrLast(s, start, s.len-1)
|
||||||
|
|
||||||
|
proc addChar(s: mstring, c: char): mstring {.compilerProc.} =
|
||||||
|
result = s
|
||||||
|
if result.len >= result.space:
|
||||||
|
result.space = resize(result.space)
|
||||||
|
result = cast[mstring](growObj(result,
|
||||||
|
sizeof(TStringDesc) + result.space * sizeof(char)))
|
||||||
|
result.data[result.len] = c
|
||||||
|
result.data[result.len+1] = '\0'
|
||||||
|
inc(result.len)
|
||||||
|
|
||||||
|
# These routines should be used like following:
|
||||||
|
# <Nimrod code>
|
||||||
|
# s &= "hallo " & name & " how do you feel?"
|
||||||
|
#
|
||||||
|
# <generated C code>
|
||||||
|
# {
|
||||||
|
# s = resizeString(s, 6 + name->len + 17);
|
||||||
|
# appendString(s, strLit1);
|
||||||
|
# appendString(s, strLit2);
|
||||||
|
# appendString(s, strLit3);
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# <Nimrod code>
|
||||||
|
# s = "hallo " & name & " how do you feel?"
|
||||||
|
#
|
||||||
|
# <generated C code>
|
||||||
|
# {
|
||||||
|
# string tmp0;
|
||||||
|
# tmp0 = rawNewString(6 + name->len + 17);
|
||||||
|
# appendString(s, strLit1);
|
||||||
|
# appendString(s, strLit2);
|
||||||
|
# appendString(s, strLit3);
|
||||||
|
# s = tmp0;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# <Nimrod code>
|
||||||
|
# s = ""
|
||||||
|
#
|
||||||
|
# <generated C code>
|
||||||
|
# s = rawNewString(0);
|
||||||
|
|
||||||
|
proc resizeString(dest: mstring, addlen: int): mstring {.compilerproc.} =
|
||||||
|
if dest.len + addLen + 1 <= dest.space: # BUGFIX: this is horrible!
|
||||||
|
result = dest
|
||||||
|
else: # slow path:
|
||||||
|
var
|
||||||
|
sp = max(resize(dest.space), dest.len + addLen + 1)
|
||||||
|
result = cast[mstring](growObj(dest, sizeof(TStringDesc) +
|
||||||
|
sp * sizeof(Char)))
|
||||||
|
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||||
|
result.space = sp
|
||||||
|
|
||||||
|
proc appendString(dest, src: mstring) {.compilerproc, inline.} =
|
||||||
|
c_memcpy(addr(dest.data[dest.len]), src.data, (src.len + 1) * sizeof(Char))
|
||||||
|
inc(dest.len, src.len)
|
||||||
|
|
||||||
|
proc appendChar(dest: mstring, c: char) {.compilerproc, inline.} =
|
||||||
|
dest.data[dest.len] = c
|
||||||
|
dest.data[dest.len+1] = '\0'
|
||||||
|
inc(dest.len)
|
||||||
|
|
||||||
|
proc setLengthStr(s: mstring, newLen: int): mstring {.compilerProc.} =
|
||||||
|
var n = max(newLen, 0)
|
||||||
|
if n <= s.space:
|
||||||
|
result = s
|
||||||
|
else:
|
||||||
|
result = resizeString(s, n)
|
||||||
|
result.len = n
|
||||||
|
result.data[n] = '\0'
|
||||||
|
|
||||||
|
# ----------------- sequences ----------------------------------------------
|
||||||
|
|
||||||
|
proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
|
||||||
|
# increments the length by one:
|
||||||
|
# this is needed for supporting the &= operator;
|
||||||
|
#
|
||||||
|
# add seq x generates:
|
||||||
|
# seq = incrSeq(seq, sizeof(x));
|
||||||
|
# seq[seq->len-1] = x;
|
||||||
|
result = seq
|
||||||
|
if result.len >= result.space:
|
||||||
|
var
|
||||||
|
s: TAddress
|
||||||
|
result.space = resize(result.space)
|
||||||
|
result = cast[PGenericSeq](growObj(result, elemSize * result.space +
|
||||||
|
GenericSeqSize))
|
||||||
|
# set new elements to zero:
|
||||||
|
s = cast[TAddress](result)
|
||||||
|
zeroMem(cast[pointer](s + GenericSeqSize + (result.len * elemSize)),
|
||||||
|
(result.space - result.len) * elemSize)
|
||||||
|
# for i in len .. space-1:
|
||||||
|
# seq->data[i] = 0
|
||||||
|
inc(result.len)
|
||||||
|
|
||||||
|
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||||
|
compilerProc.} =
|
||||||
|
result = seq
|
||||||
|
if result.space < newLen:
|
||||||
|
var
|
||||||
|
s: TAddress
|
||||||
|
result.space = max(resize(result.space), newLen)
|
||||||
|
result = cast[PGenericSeq](growObj(result, elemSize * result.space +
|
||||||
|
GenericSeqSize))
|
||||||
|
# set new elements to zero (needed for GC):
|
||||||
|
s = cast[TAddress](result)
|
||||||
|
zeroMem(cast[pointer](s + GenericSeqSize + (result.len * elemSize)),
|
||||||
|
(result.space - result.len) * elemSize)
|
||||||
|
# Else: We could decref references, if we had type information here :-(
|
||||||
|
# However, this does not happen often
|
||||||
|
result.len = newLen
|
||||||
|
|
||||||
|
# --------------- other string routines ----------------------------------
|
||||||
|
proc `$`(x: int): string =
|
||||||
|
result = newString(sizeof(x)*4)
|
||||||
|
var i = 0
|
||||||
|
var y = x
|
||||||
|
while True:
|
||||||
|
var d = y div 10
|
||||||
|
result[i] = chr(abs(int(y - d*10)) + ord('0'))
|
||||||
|
inc(i)
|
||||||
|
y = d
|
||||||
|
if y == 0: break
|
||||||
|
if x < 0:
|
||||||
|
result[i] = '-'
|
||||||
|
inc(i)
|
||||||
|
setLen(result, i)
|
||||||
|
# mirror the string:
|
||||||
|
for j in 0..i div 2 - 1:
|
||||||
|
swap(result[j], result[i-j-1])
|
||||||
|
|
||||||
|
{.push warnings: off.}
|
||||||
|
proc `$`(x: float): string =
|
||||||
|
var buf: array [0..59, char]
|
||||||
|
c_sprintf(buf, "%#g", x)
|
||||||
|
return $buf
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc `$`(x: int64): string =
|
||||||
|
# we don't rely on C's runtime here as some C compiler's
|
||||||
|
# int64 support is weak
|
||||||
|
result = newString(sizeof(x)*4)
|
||||||
|
var i = 0
|
||||||
|
var y = x
|
||||||
|
while True:
|
||||||
|
var d = y div 10
|
||||||
|
result[i] = chr(abs(int(y - d*10)) + ord('0'))
|
||||||
|
inc(i)
|
||||||
|
y = d
|
||||||
|
if y == 0: break
|
||||||
|
if x < 0:
|
||||||
|
result[i] = '-'
|
||||||
|
inc(i)
|
||||||
|
setLen(result, i)
|
||||||
|
# mirror the string:
|
||||||
|
for j in 0..i div 2 - 1:
|
||||||
|
swap(result[j], result[i-j-1])
|
||||||
|
|
||||||
|
proc `$`(x: bool): string =
|
||||||
|
if x: result = "true"
|
||||||
|
else: result = "false"
|
||||||
|
|
||||||
|
proc `$`(x: char): string =
|
||||||
|
result = newString(1)
|
||||||
|
result[0] = x
|
||||||
|
|
||||||
|
proc `$`(x: string): string =
|
||||||
|
# this is useful for generic code!
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} =
|
||||||
|
var
|
||||||
|
a = 0
|
||||||
|
b = len(x)
|
||||||
|
while a < b:
|
||||||
|
var mid = (a + b) div 2
|
||||||
|
if x[mid] < y:
|
||||||
|
a = mid + 1
|
||||||
|
else:
|
||||||
|
b = mid
|
||||||
|
if (a < len(x)) and (x[a] == y):
|
||||||
|
return a
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
1184
lib/system.nim
Executable file
1184
lib/system.nim
Executable file
File diff suppressed because it is too large
Load diff
179
lib/times.nim
Executable file
179
lib/times.nim
Executable file
|
|
@ -0,0 +1,179 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
## This module contains routines and types for dealing with time.
|
||||||
|
|
||||||
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
import
|
||||||
|
strutils
|
||||||
|
|
||||||
|
type
|
||||||
|
TMonth* = enum ## represents a month
|
||||||
|
mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
|
||||||
|
TWeekDay* = enum ## represents a weekday
|
||||||
|
dMon, dTue, dWed, dThu, dFri, dSat, dSun
|
||||||
|
|
||||||
|
TTime* {.importc: "time_t".} = record ## abstract type that represents a time
|
||||||
|
|
||||||
|
TTimeInfo* = record ## represents a time in different parts
|
||||||
|
second*: range[0..61] ## The number of seconds after the minute,
|
||||||
|
## normally in the range 0 to 59, but can
|
||||||
|
## be up to 61 to allow for leap seconds.
|
||||||
|
minute*: range[0..59] ## The number of minutes after the hour,
|
||||||
|
## in the range 0 to 59.
|
||||||
|
hour*: range[0..23] ## The number of hours past midnight,
|
||||||
|
## in the range 0 to 23.
|
||||||
|
monthday*: range[1..31] ## The day of the month, in the range 1 to 31.
|
||||||
|
month*: TMonth ## The current month.
|
||||||
|
year*: int ## The current year.
|
||||||
|
weekday*: TWeekDay ## The current day of the week.
|
||||||
|
yearday*: range[0..365] ## The number of days since January 1,
|
||||||
|
## in the range 0 to 365.
|
||||||
|
|
||||||
|
proc getTime*(): TTime ## gets the current calendar time
|
||||||
|
proc getLocalTime*(t: TTime): TTimeInfo
|
||||||
|
## converts the calendar time `t` to broken-time representation,
|
||||||
|
## expressed relative to the user's specified time zone.
|
||||||
|
proc getGMTime*(t: TTime): TTimeInfo
|
||||||
|
## converts the calendar time `t` to broken-down time representation,
|
||||||
|
## expressed in Coordinated Universal Time (UTC).
|
||||||
|
|
||||||
|
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
|
||||||
|
## converts a broken-down time structure, expressed as local time, to
|
||||||
|
## calendar time representation. The function ignores the specified
|
||||||
|
## contents of the structure members `weekday` and `yearday` and recomputes
|
||||||
|
## them from the other information in the broken-down time structure.
|
||||||
|
|
||||||
|
proc `$` *(timeInfo: TTimeInfo): string
|
||||||
|
## converts a `TTimeInfo` record to a
|
||||||
|
## string representation.
|
||||||
|
proc `$` *(time: TTime): string
|
||||||
|
## converts a calendar time to a
|
||||||
|
## string representation.
|
||||||
|
|
||||||
|
proc getDateStr*(): string
|
||||||
|
## gets the current date as a string of the format
|
||||||
|
## ``YYYY-MM-DD``.
|
||||||
|
proc getClockStr*(): string
|
||||||
|
## gets the current clock time as a string of the format ``HH:MM:SS``.
|
||||||
|
|
||||||
|
proc `-` *(a, b: TTime): int64
|
||||||
|
## computes the difference of two calendar times. Result is in seconds.
|
||||||
|
|
||||||
|
proc getStartMilsecs*(): int
|
||||||
|
## get the miliseconds from the start of the program
|
||||||
|
|
||||||
|
#implementation
|
||||||
|
|
||||||
|
# C wrapper:
|
||||||
|
type
|
||||||
|
structTM {.importc: "struct tm".} = record
|
||||||
|
second {.importc: "tm_sec".},
|
||||||
|
minute {.importc: "tm_min".},
|
||||||
|
hour {.importc: "tm_hour".},
|
||||||
|
monthday {.importc: "tm_mday".},
|
||||||
|
month {.importc: "tm_mon".},
|
||||||
|
year {.importc: "tm_year".},
|
||||||
|
weekday {.importc: "tm_wday".},
|
||||||
|
yearday {.importc: "tm_yday".},
|
||||||
|
isdst {.importc: "tm_isdst".}: cint
|
||||||
|
|
||||||
|
PTimeInfo = ptr structTM
|
||||||
|
PTime = ptr TTime
|
||||||
|
|
||||||
|
TClock {.importc: "clock_t".} = range[low(int)..high(int)]
|
||||||
|
|
||||||
|
proc localtime(timer: PTime): PTimeInfo {.
|
||||||
|
importc: "localtime", header: "<time.h>".}
|
||||||
|
proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
|
||||||
|
proc timec(timer: PTime): TTime {.importc: "time", header: "<time.h>".}
|
||||||
|
proc mktime(t: structTM): TTime {.importc: "mktime", header: "<time.h>".}
|
||||||
|
proc asctime(tblock: structTM): CString {.
|
||||||
|
importc: "asctime", header: "<time.h>".}
|
||||||
|
proc ctime(time: PTime): CString {.importc: "ctime", header: "<time.h>".}
|
||||||
|
# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
|
||||||
|
# importc: "strftime", header: "<time.h>".}
|
||||||
|
proc clock(): TClock {.importc: "clock", header: "<time.h>".}
|
||||||
|
proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
|
||||||
|
|
||||||
|
var
|
||||||
|
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
|
||||||
|
|
||||||
|
|
||||||
|
# our own procs on top of that:
|
||||||
|
proc tmToTimeInfo(tm: structTM): TTimeInfo =
|
||||||
|
const
|
||||||
|
weekDays: array [0..6, TWeekDay] = [
|
||||||
|
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
|
||||||
|
result.second = int(tm.second)
|
||||||
|
result.minute = int(tm.minute)
|
||||||
|
result.hour = int(tm.hour)
|
||||||
|
result.monthday = int(tm.monthday)
|
||||||
|
result.month = TMonth(tm.month)
|
||||||
|
result.year = tm.year + 1900
|
||||||
|
result.weekday = weekDays[int(tm.weekDay)]
|
||||||
|
result.yearday = int(tm.yearday)
|
||||||
|
|
||||||
|
proc timeInfoToTM(t: TTimeInfo): structTM =
|
||||||
|
const
|
||||||
|
weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
|
||||||
|
result.second = t.second
|
||||||
|
result.minute = t.minute
|
||||||
|
result.hour = t.hour
|
||||||
|
result.monthday = t.monthday
|
||||||
|
result.month = ord(t.month)
|
||||||
|
result.year = t.year - 1900
|
||||||
|
result.weekday = weekDays[t.weekDay]
|
||||||
|
result.yearday = t.yearday
|
||||||
|
result.isdst = -1
|
||||||
|
|
||||||
|
proc `-` (a, b: TTime): int64 =
|
||||||
|
return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but
|
||||||
|
# Nim does not support it!
|
||||||
|
|
||||||
|
proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
|
||||||
|
proc getTime(): TTime = return timec(nil)
|
||||||
|
proc getLocalTime(t: TTime): TTimeInfo =
|
||||||
|
var a = t
|
||||||
|
result = tmToTimeInfo(localtime(addr(a))^)
|
||||||
|
# copying is needed anyway to provide reentrancity; thus
|
||||||
|
# the convertion is not expensive
|
||||||
|
|
||||||
|
proc getGMTime(t: TTime): TTimeInfo =
|
||||||
|
var a = t
|
||||||
|
result = tmToTimeInfo(gmtime(addr(a))^)
|
||||||
|
# copying is needed anyway to provide reentrancity; thus
|
||||||
|
# the convertion is not expensive
|
||||||
|
|
||||||
|
proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
|
||||||
|
var cTimeInfo = timeInfo # for C++ we have to make a copy,
|
||||||
|
# because the header of mktime is broken in my version of libc
|
||||||
|
return mktime(timeInfoToTM(cTimeInfo))
|
||||||
|
|
||||||
|
proc getDateStr(): string =
|
||||||
|
var ti = getLocalTime(getTime())
|
||||||
|
result = $ti.year & "-" & intToStr(ord(ti.month)+1, 2) &
|
||||||
|
"-" & intToStr(ti.monthDay, 2)
|
||||||
|
|
||||||
|
proc getClockStr(): string =
|
||||||
|
var ti = getLocalTime(getTime())
|
||||||
|
result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
|
||||||
|
':' & intToStr(ti.second, 2)
|
||||||
|
|
||||||
|
proc `$`(timeInfo: TTimeInfo): string =
|
||||||
|
return $asctime(timeInfoToTM(timeInfo))
|
||||||
|
|
||||||
|
proc `$`(time: TTime): string =
|
||||||
|
var a = time
|
||||||
|
return $ctime(addr(a))
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
221
lib/typeinfo.nim
Executable file
221
lib/typeinfo.nim
Executable file
|
|
@ -0,0 +1,221 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# type-info module for Nimrod
|
||||||
|
|
||||||
|
include hti
|
||||||
|
|
||||||
|
proc typeid(x: any): PNimType
|
||||||
|
|
||||||
|
type
|
||||||
|
Variant = opaque record
|
||||||
|
# contains the address and a typeinfo
|
||||||
|
a: pointer # an address
|
||||||
|
k: TNimTypeKind
|
||||||
|
|
||||||
|
# conversions to any and from any are inserted by the compiler!
|
||||||
|
# x.attr is supported, as well as x[]!
|
||||||
|
# here is a special iterator for variants:
|
||||||
|
iterator fields(x: variant): (fieldname: string, value: variant) =
|
||||||
|
proc setField(structure: variant, fieldname: string, value: variant)
|
||||||
|
proc getField(structure: variant, fieldname: string)
|
||||||
|
|
||||||
|
# any is implemented as a pair (val: pointer, info: PTypeInfo)
|
||||||
|
# val is for:
|
||||||
|
# an array - its address
|
||||||
|
# a record - its address
|
||||||
|
# an object - its address
|
||||||
|
# a string - the address of the pointer to the string data
|
||||||
|
# a sequence - the address of the pointer to the sequence data
|
||||||
|
# a float - the address of a memory location where the float is stored
|
||||||
|
# this is a given address; storage comes from compiler or is
|
||||||
|
# already there (in a container)
|
||||||
|
# an int - the address of a memory location where the int is stored
|
||||||
|
# storage comes from compiler or is
|
||||||
|
# already there (in a container)
|
||||||
|
# a cstring - the address of an address of an array of chars
|
||||||
|
# a ref - the address of the ref! (not the ref itself!)
|
||||||
|
|
||||||
|
# But this does not work too well...
|
||||||
|
# Better: any is a ref to Object; than we define intObj, floatObj,
|
||||||
|
# etc.; for strings this not needed as they already fit into the
|
||||||
|
# scheme!
|
||||||
|
#
|
||||||
|
|
||||||
|
type
|
||||||
|
TAnyImpl {.exportc: "TAnyImpl".} = record
|
||||||
|
typ {.exportc: "info".}: PNimType
|
||||||
|
val {.exportc: "val".}: pointer
|
||||||
|
|
||||||
|
proc
|
||||||
|
typeKind(p: PNimType): TTypeKind {.inline.}
|
||||||
|
|
||||||
|
getAnyLength(x: any): int
|
||||||
|
|
||||||
|
isContainer(x: any): bool
|
||||||
|
|
||||||
|
writeAny(container: any, index: int, val: any)
|
||||||
|
readAny(container: any, index: int): any
|
||||||
|
|
||||||
|
writeAny(container: any, name: string, val: any)
|
||||||
|
readAny(container: any, name: string): any
|
||||||
|
|
||||||
|
getAttr(container: any, index: int, out name: string, out val: any)
|
||||||
|
|
||||||
|
getEnumStrings(enumeration: any): sequence of string
|
||||||
|
|
||||||
|
anyToInt(x: any): biggestint
|
||||||
|
anyToFloat(x: any): biggestfloat
|
||||||
|
anyToString(x: any): string
|
||||||
|
anyToChar(x: any): char
|
||||||
|
anyToBool(x: any): bool
|
||||||
|
#anyToT{T}(x: any, out result: T)
|
||||||
|
|
||||||
|
# etc...
|
||||||
|
|
||||||
|
#write(a: array of any) # also possible!
|
||||||
|
|
||||||
|
#generic proc
|
||||||
|
# deepCopy{T}(x: T): T
|
||||||
|
|
||||||
|
import
|
||||||
|
strutils
|
||||||
|
|
||||||
|
proc anyToImpl(a: any): TAnyImpl {.inline.} =
|
||||||
|
result = cast{TAnyImpl}(a)
|
||||||
|
|
||||||
|
proc typeKind(p: PNimType): TTypeKind =
|
||||||
|
result = p.typeKind
|
||||||
|
|
||||||
|
type
|
||||||
|
Pint = untraced ref int
|
||||||
|
Pint8 = untraced ref int8
|
||||||
|
Pint16 = untraced ref int16
|
||||||
|
Pint32 = untraced ref int32
|
||||||
|
Pint64 = untraced ref int64
|
||||||
|
Puint = untraced ref uint
|
||||||
|
Puint8 = untraced ref uint8
|
||||||
|
Puint16 = untraced ref uint16
|
||||||
|
Puint32 = untraced ref uint32
|
||||||
|
Puint64 = untraced ref uint64
|
||||||
|
Pfloat = untraced ref float
|
||||||
|
Pfloat32 = untraced ref float32
|
||||||
|
Pfloat64 = untraced ref float64
|
||||||
|
Pstring = untraced ref string
|
||||||
|
Pbool = untraced ref bool
|
||||||
|
Pchar = untraced ref char
|
||||||
|
|
||||||
|
proc anyToInt(x: any): biggestint =
|
||||||
|
var impl = anyToImpl(x)
|
||||||
|
case impl.typ.typeKind
|
||||||
|
of tyInt, tyEnum: result = cast{pint}(x.val)^
|
||||||
|
of tySInt8: result = cast{pint8}(x.val)^
|
||||||
|
of tySInt16: result = cast{pint16}(x.val)^
|
||||||
|
of tySInt32: result = cast{pint32}(x.val)^
|
||||||
|
of tySInt64: result = cast{pint64}(x.val)^
|
||||||
|
of tyUInt: result = cast{puint}(x.val)^
|
||||||
|
of tyUInt8: result = cast{puint8}(x.val)^
|
||||||
|
of tyUInt16: result = cast{puint16}(x.val)^
|
||||||
|
of tyUInt32: result = cast{puint32}(x.val)^
|
||||||
|
of tyUInt64: result = cast{puint64}(x.val)^
|
||||||
|
else: raise EConvertError
|
||||||
|
|
||||||
|
proc anyToFloat(x: any): biggestfloat =
|
||||||
|
var impl = anyToImpl(x)
|
||||||
|
case impl.typ.typeKind
|
||||||
|
of tyReal: result = cast{pfloat}(x.val)^
|
||||||
|
of tyReal32: result = cast{pfloat32}(x.val)^
|
||||||
|
of tyReal64: result = cast{pfloat64}(x.val)^
|
||||||
|
# of tyReal128:
|
||||||
|
else: raise EConvertError
|
||||||
|
|
||||||
|
proc anyToString(x: any): string =
|
||||||
|
var impl = anyToImpl(x)
|
||||||
|
case impl.typ.typeKind
|
||||||
|
of tyString: result = cast{pstring}(x.val)^
|
||||||
|
else: raise EConvertError
|
||||||
|
|
||||||
|
proc anyToChar(x: any): char =
|
||||||
|
var impl = anyToImpl(x)
|
||||||
|
case impl.typ.typeKind
|
||||||
|
of tyChar: result = cast{pchar}(x.val)^
|
||||||
|
else: raise EConvertError
|
||||||
|
|
||||||
|
proc anyToBool(x: any): bool =
|
||||||
|
var impl = anyToImpl(x)
|
||||||
|
case impl.typ.typeKind
|
||||||
|
of tyBool: result = cast{pbool}(x.val)^
|
||||||
|
else: raise EConvertError
|
||||||
|
|
||||||
|
proc getAnyLength(x: any): int =
|
||||||
|
result = anyToImpl(x).typ.len
|
||||||
|
|
||||||
|
const
|
||||||
|
ContainerSet = {tyArray, tyRecord, tyObject, tyOpenArray, tySequence, tyTable}
|
||||||
|
|
||||||
|
proc isContainer(x: any): bool =
|
||||||
|
result = anyToImpl(x).typ.typeKind in ContainerSet
|
||||||
|
|
||||||
|
proc strcmp(a, b: cstring): int {.external: "strcmp", nodecl.}
|
||||||
|
|
||||||
|
proc strToIndex(info: PTypeInfo, str: string): int =
|
||||||
|
for i in 0..typ.len-1:
|
||||||
|
if strcmp(info.slots[i].name, str) == 0:
|
||||||
|
return i
|
||||||
|
raise EConvertError
|
||||||
|
|
||||||
|
proc writeAny(container: any, index: int, val: any) =
|
||||||
|
var x = anyToImpl(container)
|
||||||
|
if index >= 0 and index < container.len:
|
||||||
|
case x.typ.typeKind
|
||||||
|
of tySequence:
|
||||||
|
var u = cast{TAddress}(x.val)
|
||||||
|
genericAssignAux(cast{pointer}(u) +% x.typ.slots[index].offset +%
|
||||||
|
GenericSeqSize,
|
||||||
|
anyToImpl(val).val, u.typ.baseType)
|
||||||
|
of tyArray:
|
||||||
|
of tyRecord, tyObject:
|
||||||
|
else: raise EConvertError
|
||||||
|
else:
|
||||||
|
raise EIndexError
|
||||||
|
|
||||||
|
|
||||||
|
proc readAny(container: any, index: int): any =
|
||||||
|
var x = anyToImpl(container)
|
||||||
|
if x.typ.typeKind in ContainerSet:
|
||||||
|
if index >= 0 and index < container.len:
|
||||||
|
# XXX
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise EIndexError
|
||||||
|
else:
|
||||||
|
raise EConvertError
|
||||||
|
|
||||||
|
proc writeAny(container: any, name: string, val: any) =
|
||||||
|
result = writeAny(container, strToIndex(anyToImpl(container).typ), val)
|
||||||
|
|
||||||
|
proc readAny(container: any, name: string): any =
|
||||||
|
result = readAny(container, strToIndex(anyToImpl(container).typ))
|
||||||
|
|
||||||
|
proc getAttr(container: any, index: int, out name: string, out val: any) =
|
||||||
|
var x = anyToImpl(container)
|
||||||
|
if x.typ.typeKind in ContainerSet:
|
||||||
|
val = readAny(container, index)
|
||||||
|
name = $x.typ.slots[index].name
|
||||||
|
else:
|
||||||
|
raise EConvertError
|
||||||
|
|
||||||
|
proc getEnumStrings(enumeration: any): sequence of string =
|
||||||
|
result = []
|
||||||
|
var x = anyToImpl(enumeration)
|
||||||
|
if x.typ.typekind == tyEnum:
|
||||||
|
for i in 0 .. x.typ.len-1:
|
||||||
|
result &= $x.typ.slots[i].name
|
||||||
|
else:
|
||||||
|
raise EConvertError
|
||||||
103
lib/unicode.nim
Executable file
103
lib/unicode.nim
Executable file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
type
|
||||||
|
TUniChar* = int32 ## type that can hold any Unicode character
|
||||||
|
TUniChar16* = int16 ##
|
||||||
|
|
||||||
|
template ones(n) = ((1 shl n)-1)
|
||||||
|
|
||||||
|
proc uniCharLen*(s: string): int =
|
||||||
|
## returns the number of Unicode characters of the string `s`.
|
||||||
|
var i = 0
|
||||||
|
while i < len(s):
|
||||||
|
if ord(s[i]) <= 127:
|
||||||
|
inc(i)
|
||||||
|
elif ord(s[i]) shr 5 == 0b110:
|
||||||
|
inc(i, 2)
|
||||||
|
elif ord(s[i]) shr 4 == 0b1110:
|
||||||
|
inc(i, 3)
|
||||||
|
elif ord(s[i]) shr 3 == 0b11110:
|
||||||
|
inc(i, 4)
|
||||||
|
else:
|
||||||
|
assert(false)
|
||||||
|
inc(result)
|
||||||
|
|
||||||
|
proc uniCharAt*(s: string, i: int): TUniChar =
|
||||||
|
if ord(s[i]) <= 127:
|
||||||
|
result = ord(s[i])
|
||||||
|
elif ord(s[i]) shr 5 == 0b110:
|
||||||
|
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
|
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||||
|
elif ord(s[i]) shr 4 == 0b1110:
|
||||||
|
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
|
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
|
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||||
|
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||||
|
(ord(s[i+2]) and ones(6))
|
||||||
|
elif ord(s[i]) shr 3 == 0b11110:
|
||||||
|
assert(ord(s[i+1]) shr 6 == 0b10)
|
||||||
|
assert(ord(s[i+2]) shr 6 == 0b10)
|
||||||
|
assert(ord(s[i+3]) shr 6 == 0b10)
|
||||||
|
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||||
|
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||||
|
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||||
|
(ord(s[i+3]) and ones(6))
|
||||||
|
else:
|
||||||
|
assert(false)
|
||||||
|
|
||||||
|
iterator unichars*(s: string): TUniChar =
|
||||||
|
## iterates over any unicode character of the string `s`. Fastest possible
|
||||||
|
## method.
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
result: TUniChar
|
||||||
|
while i < len(s):
|
||||||
|
if ord(s[i]) <= 127:
|
||||||
|
result = ord(s[i])
|
||||||
|
inc(i)
|
||||||
|
elif ord(s[i]) shr 5 == 0b110:
|
||||||
|
result = (ord(s[i]) and ones(5)) shl 6 or (ord(s[i+1]) and ones(6))
|
||||||
|
inc(i, 2)
|
||||||
|
elif ord(s[i]) shr 4 == 0b1110:
|
||||||
|
result = (ord(s[i]) and ones(4)) shl 12 or
|
||||||
|
(ord(s[i+1]) and ones(6)) shl 6 or
|
||||||
|
(ord(s[i+2]) and ones(6))
|
||||||
|
inc(i, 3)
|
||||||
|
elif ord(s[i]) shr 3 == 0b11110:
|
||||||
|
result = (ord(s[i]) and ones(3)) shl 18 or
|
||||||
|
(ord(s[i+1]) and ones(6)) shl 12 or
|
||||||
|
(ord(s[i+2]) and ones(6)) shl 6 or
|
||||||
|
(ord(s[i+3]) and ones(6))
|
||||||
|
inc(i, 4)
|
||||||
|
else:
|
||||||
|
assert(false)
|
||||||
|
yield result
|
||||||
|
|
||||||
|
proc utf8toLocale*(s: string): string
|
||||||
|
proc localeToUtf8*(s: string): string
|
||||||
|
|
||||||
|
proc utf8toUtf16*(s: string): seq[TUniChar16]
|
||||||
|
proc utf8toUcs4*(s: string): seq[TUniChar] =
|
||||||
|
result = []
|
||||||
|
for u in unichars(s):
|
||||||
|
|
||||||
|
proc ucs4ToUtf8(s: seq[TUnichar]): string
|
||||||
|
proc utf16ToUtf8(s: seq[TUnichar16]): string
|
||||||
|
proc ucs4toUft16(s: seq[TUnichar]): seq[TUnichar16]
|
||||||
|
proc uft16toUcs4(s: seq[Tunichar16]): seq[TUnichar]
|
||||||
|
|
||||||
|
proc cmpUnicode*(a, b: string): int =
|
||||||
|
## treats `a` and `b` as UTF-8 strings and compares them. Returns:
|
||||||
|
## | < 0 iff a < b
|
||||||
|
## | > 0 iff a > b
|
||||||
|
## | == 0 iff a == b
|
||||||
|
## This routine is useful for sorting UTF-8 strings.
|
||||||
|
return -1
|
||||||
|
|
||||||
2656
lib/windows/mmsystem.nim
Executable file
2656
lib/windows/mmsystem.nim
Executable file
File diff suppressed because it is too large
Load diff
230
lib/windows/nb30.nim
Executable file
230
lib/windows/nb30.nim
Executable file
|
|
@ -0,0 +1,230 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
# NetBIOS 3.0 interface unit
|
||||||
|
|
||||||
|
# This unit contains the definitions for portable NetBIOS 3.0 support.
|
||||||
|
|
||||||
|
import # Data structure templates
|
||||||
|
Windows
|
||||||
|
|
||||||
|
const
|
||||||
|
NCBNAMSZ* = 16 # absolute length of a net name
|
||||||
|
MAX_LANA* = 254 # lana's in range 0 to MAX_LANA inclusive
|
||||||
|
|
||||||
|
type # Network Control Block
|
||||||
|
PNCB* = ptr TNCB
|
||||||
|
TNCBPostProc* = proc (P: PNCB)
|
||||||
|
TNCB* = record # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
|
||||||
|
# by an array of NAME_BUFFER structures.
|
||||||
|
ncb_command*: Char # command code
|
||||||
|
ncb_retcode*: Char # return code
|
||||||
|
ncb_lsn*: Char # local session number
|
||||||
|
ncb_num*: Char # number of our network name
|
||||||
|
ncb_buffer*: cstring # address of message buffer
|
||||||
|
ncb_length*: int16 # size of message buffer
|
||||||
|
ncb_callname*: array[0..NCBNAMSZ - 1, char] # blank-padded name of remote
|
||||||
|
ncb_name*: array[0..NCBNAMSZ - 1, char] # our blank-padded netname
|
||||||
|
ncb_rto*: Char # rcv timeout/retry count
|
||||||
|
ncb_sto*: Char # send timeout/sys timeout
|
||||||
|
ncb_post*: TNCBPostProc # POST routine address
|
||||||
|
ncb_lana_num*: Char # lana (adapter) number
|
||||||
|
ncb_cmd_cplt*: Char # 0xff => commmand pending
|
||||||
|
ncb_reserve*: array[0..9, Char] # reserved, used by BIOS
|
||||||
|
ncb_event*: THandle # HANDLE to Win32 event which
|
||||||
|
# will be set to the signalled
|
||||||
|
# state when an ASYNCH command
|
||||||
|
# completes
|
||||||
|
|
||||||
|
PAdapterStatus* = ptr TAdapterStatus
|
||||||
|
TAdapterStatus* = record
|
||||||
|
adapter_address*: array[0..5, Char]
|
||||||
|
rev_major*: Char
|
||||||
|
reserved0*: Char
|
||||||
|
adapter_type*: Char
|
||||||
|
rev_minor*: Char
|
||||||
|
duration*: int16
|
||||||
|
frmr_recv*: int16
|
||||||
|
frmr_xmit*: int16
|
||||||
|
iframe_recv_err*: int16
|
||||||
|
xmit_aborts*: int16
|
||||||
|
xmit_success*: DWORD
|
||||||
|
recv_success*: DWORD
|
||||||
|
iframe_xmit_err*: int16
|
||||||
|
recv_buff_unavail*: int16
|
||||||
|
t1_timeouts*: int16
|
||||||
|
ti_timeouts*: int16
|
||||||
|
reserved1*: DWORD
|
||||||
|
free_ncbs*: int16
|
||||||
|
max_cfg_ncbs*: int16
|
||||||
|
max_ncbs*: int16
|
||||||
|
xmit_buf_unavail*: int16
|
||||||
|
max_dgram_size*: int16
|
||||||
|
pending_sess*: int16
|
||||||
|
max_cfg_sess*: int16
|
||||||
|
max_sess*: int16
|
||||||
|
max_sess_pkt_size*: int16
|
||||||
|
name_count*: int16
|
||||||
|
|
||||||
|
PNameBuffer* = ptr TNameBuffer
|
||||||
|
TNameBuffer* = record
|
||||||
|
name*: array[0..NCBNAMSZ - 1, Char]
|
||||||
|
name_num*: Char
|
||||||
|
name_flags*: Char
|
||||||
|
|
||||||
|
|
||||||
|
const # values for name_flags bits.
|
||||||
|
NAME_FLAGS_MASK* = 0x00000087
|
||||||
|
GROUP_NAME* = 0x00000080
|
||||||
|
UNIQUE_NAME* = 0x00000000
|
||||||
|
REGISTERING* = 0x00000000
|
||||||
|
REGISTERED* = 0x00000004
|
||||||
|
DEREGISTERED* = 0x00000005
|
||||||
|
DUPLICATE* = 0x00000006
|
||||||
|
DUPLICATE_DEREG* = 0x00000007
|
||||||
|
|
||||||
|
type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
|
||||||
|
# by an array of SESSION_BUFFER structures. If the NCB_NAME starts with an
|
||||||
|
# asterisk then an array of these structures is returned containing the
|
||||||
|
# status for all names.
|
||||||
|
PSessionHeader* = ptr TSessionHeader
|
||||||
|
TSessionHeader* = record
|
||||||
|
sess_name*: Char
|
||||||
|
num_sess*: Char
|
||||||
|
rcv_dg_outstanding*: Char
|
||||||
|
rcv_any_outstanding*: Char
|
||||||
|
|
||||||
|
PSessionBuffer* = ptr TSessionBuffer
|
||||||
|
TSessionBuffer* = record
|
||||||
|
lsn*: Char
|
||||||
|
state*: Char
|
||||||
|
local_name*: array[0..NCBNAMSZ - 1, Char]
|
||||||
|
remote_name*: array[0..NCBNAMSZ - 1, Char]
|
||||||
|
rcvs_outstanding*: Char
|
||||||
|
sends_outstanding*: Char
|
||||||
|
|
||||||
|
|
||||||
|
const # Values for state
|
||||||
|
LISTEN_OUTSTANDING* = 0x00000001
|
||||||
|
CALL_PENDING* = 0x00000002
|
||||||
|
SESSION_ESTABLISHED* = 0x00000003
|
||||||
|
HANGUP_PENDING* = 0x00000004
|
||||||
|
HANGUP_COMPLETE* = 0x00000005
|
||||||
|
SESSION_ABORTED* = 0x00000006
|
||||||
|
|
||||||
|
type # Structure returned to the NCB command NCBENUM.
|
||||||
|
# On a system containing lana's 0, 2 and 3, a structure with
|
||||||
|
# length =3, lana[0]=0, lana[1]=2 and lana[2]=3 will be returned.
|
||||||
|
PLanaEnum* = ptr TLanaEnum
|
||||||
|
TLanaEnum* = record # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
|
||||||
|
# by an array of FIND_NAME_BUFFER structures.
|
||||||
|
len*: Char # Number of valid entries in lana[]
|
||||||
|
lana*: array[0..MAX_LANA, Char]
|
||||||
|
|
||||||
|
PFindNameHeader* = ptr TFindNameHeader
|
||||||
|
TFindNameHeader* = record
|
||||||
|
node_count*: int16
|
||||||
|
reserved*: Char
|
||||||
|
unique_group*: Char
|
||||||
|
|
||||||
|
PFindNameBuffer* = ptr TFindNameBuffer
|
||||||
|
TFindNameBuffer* = record # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
|
||||||
|
# transport specific extensions to netbios.
|
||||||
|
len*: Char
|
||||||
|
access_control*: Char
|
||||||
|
frame_control*: Char
|
||||||
|
destination_addr*: array[0..5, Char]
|
||||||
|
source_addr*: array[0..5, Char]
|
||||||
|
routing_info*: array[0..17, Char]
|
||||||
|
|
||||||
|
PActionHeader* = ptr TActionHeader
|
||||||
|
TActionHeader* = record
|
||||||
|
transport_id*: int32
|
||||||
|
action_code*: int16
|
||||||
|
reserved*: int16
|
||||||
|
|
||||||
|
|
||||||
|
const # Values for transport_id
|
||||||
|
ALL_TRANSPORTS* = "M\0\0\0"
|
||||||
|
MS_NBF* = "MNBF" # Special values and constants
|
||||||
|
|
||||||
|
const # NCB Command codes
|
||||||
|
NCBCALL* = 0x00000010 # NCB CALL
|
||||||
|
NCBLISTEN* = 0x00000011 # NCB LISTEN
|
||||||
|
NCBHANGUP* = 0x00000012 # NCB HANG UP
|
||||||
|
NCBSEND* = 0x00000014 # NCB SEND
|
||||||
|
NCBRECV* = 0x00000015 # NCB RECEIVE
|
||||||
|
NCBRECVANY* = 0x00000016 # NCB RECEIVE ANY
|
||||||
|
NCBCHAINSEND* = 0x00000017 # NCB CHAIN SEND
|
||||||
|
NCBDGSEND* = 0x00000020 # NCB SEND DATAGRAM
|
||||||
|
NCBDGRECV* = 0x00000021 # NCB RECEIVE DATAGRAM
|
||||||
|
NCBDGSENDBC* = 0x00000022 # NCB SEND BROADCAST DATAGRAM
|
||||||
|
NCBDGRECVBC* = 0x00000023 # NCB RECEIVE BROADCAST DATAGRAM
|
||||||
|
NCBADDNAME* = 0x00000030 # NCB ADD NAME
|
||||||
|
NCBDELNAME* = 0x00000031 # NCB DELETE NAME
|
||||||
|
NCBRESET* = 0x00000032 # NCB RESET
|
||||||
|
NCBASTAT* = 0x00000033 # NCB ADAPTER STATUS
|
||||||
|
NCBSSTAT* = 0x00000034 # NCB SESSION STATUS
|
||||||
|
NCBCANCEL* = 0x00000035 # NCB CANCEL
|
||||||
|
NCBADDGRNAME* = 0x00000036 # NCB ADD GROUP NAME
|
||||||
|
NCBENUM* = 0x00000037 # NCB ENUMERATE LANA NUMBERS
|
||||||
|
NCBUNLINK* = 0x00000070 # NCB UNLINK
|
||||||
|
NCBSENDNA* = 0x00000071 # NCB SEND NO ACK
|
||||||
|
NCBCHAINSENDNA* = 0x00000072 # NCB CHAIN SEND NO ACK
|
||||||
|
NCBLANSTALERT* = 0x00000073 # NCB LAN STATUS ALERT
|
||||||
|
NCBACTION* = 0x00000077 # NCB ACTION
|
||||||
|
NCBFINDNAME* = 0x00000078 # NCB FIND NAME
|
||||||
|
NCBTRACE* = 0x00000079 # NCB TRACE
|
||||||
|
ASYNCH* = 0x00000080 # high bit set = asynchronous
|
||||||
|
# NCB Return codes
|
||||||
|
NRC_GOODRET* = 0x00000000 # good return
|
||||||
|
# also returned when ASYNCH request accepted
|
||||||
|
NRC_BUFLEN* = 0x00000001 # illegal buffer length
|
||||||
|
NRC_ILLCMD* = 0x00000003 # illegal command
|
||||||
|
NRC_CMDTMO* = 0x00000005 # command timed out
|
||||||
|
NRC_INCOMP* = 0x00000006 # message incomplete, issue another command
|
||||||
|
NRC_BADDR* = 0x00000007 # illegal buffer address
|
||||||
|
NRC_SNUMOUT* = 0x00000008 # session number out of range
|
||||||
|
NRC_NORES* = 0x00000009 # no resource available
|
||||||
|
NRC_SCLOSED* = 0x0000000A # session closed
|
||||||
|
NRC_CMDCAN* = 0x0000000B # command cancelled
|
||||||
|
NRC_DUPNAME* = 0x0000000D # duplicate name
|
||||||
|
NRC_NAMTFUL* = 0x0000000E # name table full
|
||||||
|
NRC_ACTSES* = 0x0000000F # no deletions, name has active sessions
|
||||||
|
NRC_LOCTFUL* = 0x00000011 # local session table full
|
||||||
|
NRC_REMTFUL* = 0x00000012 # remote session table full
|
||||||
|
NRC_ILLNN* = 0x00000013 # illegal name number
|
||||||
|
NRC_NOCALL* = 0x00000014 # no callname
|
||||||
|
NRC_NOWILD* = 0x00000015 # cannot put * in NCB_NAME
|
||||||
|
NRC_INUSE* = 0x00000016 # name in use on remote adapter
|
||||||
|
NRC_NAMERR* = 0x00000017 # name deleted
|
||||||
|
NRC_SABORT* = 0x00000018 # session ended abnormally
|
||||||
|
NRC_NAMCONF* = 0x00000019 # name conflict detected
|
||||||
|
NRC_IFBUSY* = 0x00000021 # interface busy, IRET before retrying
|
||||||
|
NRC_TOOMANY* = 0x00000022 # too many commands outstanding, retry later
|
||||||
|
NRC_BRIDGE* = 0x00000023 # NCB_lana_num field invalid
|
||||||
|
NRC_CANOCCR* = 0x00000024 # command completed while cancel occurring
|
||||||
|
NRC_CANCEL* = 0x00000026 # command not valid to cancel
|
||||||
|
NRC_DUPENV* = 0x00000030 # name defined by anther local process
|
||||||
|
NRC_ENVNOTDEF* = 0x00000034 # environment undefined. RESET required
|
||||||
|
NRC_OSRESNOTAV* = 0x00000035 # required OS resources exhausted
|
||||||
|
NRC_MAXAPPS* = 0x00000036 # max number of applications exceeded
|
||||||
|
NRC_NOSAPS* = 0x00000037 # no saps available for netbios
|
||||||
|
NRC_NORESOURCES* = 0x00000038 # requested resources are not available
|
||||||
|
NRC_INVADDRESS* = 0x00000039 # invalid ncb address or length > segment
|
||||||
|
NRC_INVDDID* = 0x0000003B # invalid NCB DDID
|
||||||
|
NRC_LOCKFAIL* = 0x0000003C # lock of user area failed
|
||||||
|
NRC_OPENERR* = 0x0000003F # NETBIOS not loaded
|
||||||
|
NRC_SYSTEM* = 0x00000040 # system error
|
||||||
|
NRC_PENDING* = 0x000000FF # asynchronous command is not yet finished
|
||||||
|
# main user entry point for NetBIOS 3.0
|
||||||
|
# Usage: Result = Netbios( pncb );
|
||||||
|
|
||||||
|
proc Netbios*(P: PNCB): Char{.stdcall, dynlib: "netapi32.dll",
|
||||||
|
importc: "Netbios".}
|
||||||
|
# implementation
|
||||||
208
lib/windows/ole2.nim
Executable file
208
lib/windows/ole2.nim
Executable file
|
|
@ -0,0 +1,208 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2006 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
import
|
||||||
|
windows
|
||||||
|
|
||||||
|
const
|
||||||
|
GUID_NULL*: TGUID = (D1: 0x00000000, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000])
|
||||||
|
IID_IUnknown*: TGUID = (D1: 0x00000000, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IClassFactory*: TGUID = (D1: 0x00000001, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IMarshal*: TGUID = (D1: 0x00000003, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IMalloc*: TGUID = (D1: 0x00000002, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IStdMarshalInfo*: TGUID = (D1: 0x00000018, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IExternalConnection*: TGUID = (D1: 0x00000019, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IEnumUnknown*: TGUID = (D1: 0x00000100, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IBindCtx*: TGUID = (D1: 0x0000000E, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumMoniker*: TGUID = (D1: 0x00000102, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IRunnableObject*: TGUID = (D1: 0x00000126, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IRunningObjectTable*: TGUID = (D1: 0x00000010, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IPersist*: TGUID = (D1: 0x0000010C, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IPersistStream*: TGUID = (D1: 0x00000109, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IMoniker*: TGUID = (D1: 0x0000000F, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumString*: TGUID = (D1: 0x00000101, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IStream*: TGUID = (D1: 0x0000000C, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumStatStg*: TGUID = (D1: 0x0000000D, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IStorage*: TGUID = (D1: 0x0000000B, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IPersistFile*: TGUID = (D1: 0x0000010B, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IPersistStorage*: TGUID = (D1: 0x0000010A, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_ILockBytes*: TGUID = (D1: 0x0000000A, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumFormatEtc*: TGUID = (D1: 0x00000103, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumStatData*: TGUID = (D1: 0x00000105, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IRootStorage*: TGUID = (D1: 0x00000012, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IAdviseSink*: TGUID = (D1: 0x0000010F, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IAdviseSink2*: TGUID = (D1: 0x00000125, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IDataObject*: TGUID = (D1: 0x0000010E, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IDataAdviseHolder*: TGUID = (D1: 0x00000110, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IMessageFilter*: TGUID = (D1: 0x00000016, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IRpcChannelBuffer*: TGUID = (D1: 0xD5F56B60, D2: 0x0000593B,
|
||||||
|
D3: 0x0000101A, D4: [0x000000B5, 0x00000069, 0x00000008, 0x00000000,
|
||||||
|
0x0000002B, 0x0000002D, 0x000000BF, 0x0000007A])
|
||||||
|
IID_IRpcProxyBuffer*: TGUID = (D1: 0xD5F56A34, D2: 0x0000593B, D3: 0x0000101A, D4: [
|
||||||
|
0x000000B5, 0x00000069, 0x00000008, 0x00000000, 0x0000002B, 0x0000002D,
|
||||||
|
0x000000BF, 0x0000007A])
|
||||||
|
IID_IRpcStubBuffer*: TGUID = (D1: 0xD5F56AFC, D2: 0x0000593B, D3: 0x0000101A, D4: [
|
||||||
|
0x000000B5, 0x00000069, 0x00000008, 0x00000000, 0x0000002B, 0x0000002D,
|
||||||
|
0x000000BF, 0x0000007A])
|
||||||
|
IID_IPSFactoryBuffer*: TGUID = (D1: 0xD5F569D0, D2: 0x0000593B,
|
||||||
|
D3: 0x0000101A, D4: [0x000000B5, 0x00000069, 0x00000008, 0x00000000,
|
||||||
|
0x0000002B, 0x0000002D, 0x000000BF, 0x0000007A])
|
||||||
|
IID_ICreateTypeInfo*: TGUID = (D1: 0x00020405, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_ICreateTypeLib*: TGUID = (D1: 0x00020406, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IDispatch*: TGUID = (D1: 0x00020400, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumVariant*: TGUID = (D1: 0x00020404, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_ITypeComp*: TGUID = (D1: 0x00020403, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_ITypeInfo*: TGUID = (D1: 0x00020401, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_ITypeLib*: TGUID = (D1: 0x00020402, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IErrorInfo*: TGUID = (D1: 0x1CF2B120, D2: 0x0000547D, D3: 0x0000101B, D4: [
|
||||||
|
0x0000008E, 0x00000065, 0x00000008, 0x00000000, 0x0000002B, 0x0000002B,
|
||||||
|
0x000000D1, 0x00000019])
|
||||||
|
IID_ICreateErrorInfo*: TGUID = (D1: 0x22F03340, D2: 0x0000547D,
|
||||||
|
D3: 0x0000101B, D4: [0x0000008E, 0x00000065, 0x00000008, 0x00000000,
|
||||||
|
0x0000002B, 0x0000002B, 0x000000D1, 0x00000019])
|
||||||
|
IID_ISupportErrorInfo*: TGUID = (D1: 0xDF0B3D60, D2: 0x0000548F,
|
||||||
|
D3: 0x0000101B, D4: [0x0000008E, 0x00000065, 0x00000008, 0x00000000,
|
||||||
|
0x0000002B, 0x0000002B, 0x000000D1, 0x00000019])
|
||||||
|
IID_IOleAdviseHolder*: TGUID = (D1: 0x00000111, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleCache*: TGUID = (D1: 0x0000011E, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleCache2*: TGUID = (D1: 0x00000128, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleCacheControl*: TGUID = (D1: 0x00000129, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IParseDisplayName*: TGUID = (D1: 0x0000011A, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleContainer*: TGUID = (D1: 0x0000011B, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleClientSite*: TGUID = (D1: 0x00000118, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleObject*: TGUID = (D1: 0x00000112, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleWindow*: TGUID = (D1: 0x00000114, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleLink*: TGUID = (D1: 0x0000011D, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IOleItemContainer*: TGUID = (D1: 0x0000011C, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleInPlaceUIWindow*: TGUID = (D1: 0x00000115, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleInPlaceActiveObject*: TGUID = (D1: 0x00000117, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleInPlaceFrame*: TGUID = (D1: 0x00000116, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleInPlaceObject*: TGUID = (D1: 0x00000113, D2: 0x00000000,
|
||||||
|
D3: 0x00000000, D4: [0x000000C0, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000046])
|
||||||
|
IID_IOleInPlaceSite*: TGUID = (D1: 0x00000119, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IViewObject*: TGUID = (D1: 0x0000010D, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IViewObject2*: TGUID = (D1: 0x00000127, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IDropSource*: TGUID = (D1: 0x00000121, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IDropTarget*: TGUID = (D1: 0x00000122, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
|
IID_IEnumOleVerb*: TGUID = (D1: 0x00000104, D2: 0x00000000, D3: 0x00000000, D4: [
|
||||||
|
0x000000C0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000046])
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue