Merge pull request #66 from jck/cleanup
How did you fix this one? Seems there were no new commits?
2
.gitignore
vendored
@ -9,10 +9,12 @@ build/
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
*egg-info/
|
*egg-info/
|
||||||
dist/
|
dist/
|
||||||
|
.tox
|
||||||
|
|
||||||
# Cosim
|
# Cosim
|
||||||
*.o
|
*.o
|
||||||
*.vpi
|
*.vpi
|
||||||
|
*.so
|
||||||
|
|
||||||
# Simulator generated files
|
# Simulator generated files
|
||||||
*.vcd
|
*.vcd
|
||||||
|
@ -31,7 +31,7 @@ matrix:
|
|||||||
- python: "3.4"
|
- python: "3.4"
|
||||||
env: CI_TARGET=ghdl
|
env: CI_TARGET=ghdl
|
||||||
|
|
||||||
script: ./ci.sh
|
script: ./scripts/ci.sh
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
6
Makefile
@ -4,6 +4,12 @@ install:
|
|||||||
localinstall:
|
localinstall:
|
||||||
python setup.py install --home=$(HOME)
|
python setup.py install --home=$(HOME)
|
||||||
|
|
||||||
|
docs:
|
||||||
|
tox -e docs html
|
||||||
|
|
||||||
|
livedocs:
|
||||||
|
tox -e docs livehtml
|
||||||
|
|
||||||
release:
|
release:
|
||||||
- rm MANIFEST
|
- rm MANIFEST
|
||||||
- rm CHANGELOG.txt
|
- rm CHANGELOG.txt
|
||||||
|
@ -19,6 +19,7 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
|||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " livehtml to make continuously updating standalone HTML files"
|
||||||
@echo " web to make files usable by Sphinx.web"
|
@echo " web to make files usable by Sphinx.web"
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
@ -41,6 +42,10 @@ html:
|
|||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in build/html."
|
@echo "Build finished. The HTML pages are in build/html."
|
||||||
|
|
||||||
|
livehtml:
|
||||||
|
mkdir -p build/html build/doctrees
|
||||||
|
sphinx-autobuild -b html $(ALLSPHINXOPTS) build/html
|
||||||
|
|
||||||
web:
|
web:
|
||||||
mkdir -p build/web build/doctrees
|
mkdir -p build/web build/doctrees
|
||||||
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web
|
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web
|
||||||
|
398
doc/source/whatsnew/0.3.rst
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
=======================
|
||||||
|
What’s New in MyHDL 0.3
|
||||||
|
=======================
|
||||||
|
|
||||||
|
:Author: Jan Decaluwe
|
||||||
|
|
||||||
|
VCD output for waveform viewing
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|image|
|
||||||
|
|
||||||
|
MyHDL now has support for waveform viewing. During simulation, signal
|
||||||
|
changes can be written to a VCD output file that can be loaded into a
|
||||||
|
waveform viewer tool such as **gtkwave**.
|
||||||
|
|
||||||
|
The user interface of this feature consists of a single function,
|
||||||
|
:func:`traceSignals()`. To explain how it works, recall that in MyHDL,
|
||||||
|
an instance is created by assigning the result of a function call to an
|
||||||
|
instance name. For example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tb_fsm = testbench()
|
||||||
|
|
||||||
|
To enable VCD tracing, the instance should be created as follows
|
||||||
|
instead:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tb_fsm = traceSignals(testbench)
|
||||||
|
|
||||||
|
All signals in the instance hierarchy will be traced in a VCD file
|
||||||
|
called . Note that first the argument of :func:`traceSignals()` consists
|
||||||
|
of the uncalled function. By calling the function under its control,
|
||||||
|
:func:`traceSignals()` gathers information about the hierarchy and the
|
||||||
|
signals to be traced. In addition to a function argument,
|
||||||
|
:func:`traceSignals()` accepts an arbitrary number of non-keyword and
|
||||||
|
keyword arguments that will be passed to the function call.
|
||||||
|
|
||||||
|
Signals are dumped in a suitable format. This format is inferred at the
|
||||||
|
:class:`Signal` construction time, from the type of the initial value.
|
||||||
|
In particular, :class:`bool` signals are dumped as single bits. (This
|
||||||
|
only works starting with Python 2.3, when :class:`bool` has become a
|
||||||
|
separate type). Likewise, :class:`intbv` signals with a defined bit
|
||||||
|
width are dumped as bit vectors. To support the general case, other
|
||||||
|
types of signals are dumped as a string representation, as returned by
|
||||||
|
the standard :func:`str()` function.
|
||||||
|
|
||||||
|
[warning] Support for literal string representations is not part of the
|
||||||
|
VCD standard. It is specific to **gtkwave**. To generate a standard VCD
|
||||||
|
file, you need to use signals with a defined bit width only.
|
||||||
|
|
||||||
|
Enumeration types
|
||||||
|
=================
|
||||||
|
|
||||||
|
It is often desirable to define a set of identifiers. A standard Python
|
||||||
|
idiom for this purpose is to assign a range of integers to a tuple of
|
||||||
|
identifiers, like so:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> SEARCH, CONFIRM, SYNC = range(3)
|
||||||
|
>>> CONFIRM
|
||||||
|
1
|
||||||
|
|
||||||
|
However, this technique has some drawbacks. Though it is clearly the
|
||||||
|
intention that the identifiers belong together, this information is lost
|
||||||
|
as soon as they are defined. Also, the identifiers evaluate to integers,
|
||||||
|
whereas a string representation of the identifiers would be preferable.
|
||||||
|
To solve these issues, we need an *enumeration type*.
|
||||||
|
|
||||||
|
MyHDL 0.3 supports enumeration types by providing a function
|
||||||
|
:func:`enum()`. The arguments to :func:`enum()` are the string
|
||||||
|
representations of the identifiers, and its return value is an
|
||||||
|
enumeration type. The identifiers are available as attributes of the
|
||||||
|
type. For example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> from myhdl import enum
|
||||||
|
>>> t_State = enum('SEARCH', 'CONFIRM', 'SYNC')
|
||||||
|
>>> t_State
|
||||||
|
<Enum: SEARCH, CONFIRM, SYNC>
|
||||||
|
>>> t_State.CONFIRM
|
||||||
|
CONFIRM
|
||||||
|
|
||||||
|
Enumeration types are often used for the state variable in a finite
|
||||||
|
state machine. In the waveform in
|
||||||
|
Section \ `1 <#vcd-output-for-waveform-viewing>`__, you see a
|
||||||
|
:class:`Signal` called ``state``. Note how the waveforms show the string
|
||||||
|
representation of the enumeration type identifiers The ``state`` signal
|
||||||
|
has been constructed with an enumeration type identifier as its initial
|
||||||
|
value, as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
state = Signal(t_State.SEARCH)
|
||||||
|
|
||||||
|
Inferring the sensitivity list for combinatorial logic
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
In MyHDL, combinatorial logic is described by a generator function with
|
||||||
|
a sensitivity list that contains all inputs signals (the signals that
|
||||||
|
are read inside the function).
|
||||||
|
|
||||||
|
It may be easy to forget some input signals, especially it there are a
|
||||||
|
lot of them or if the code is being modified. There are various ways to
|
||||||
|
solve this. One way is to use a sophisticated editor. Another way is
|
||||||
|
direct language support. For example, recent versions of Verilog have
|
||||||
|
the ``always @*`` construct, that infers all input signals. The
|
||||||
|
SystemVerilog 3.1 standard improves on this by introducing the
|
||||||
|
``always_comb`` block with slightly enhanced semantics.
|
||||||
|
|
||||||
|
MyHDL 0.3 provides a function called :func:`always_comb()` which is
|
||||||
|
named and modeled after the SystemVerilog counterpart.
|
||||||
|
:func:`always_comb()` takes a classic local function as its argument.
|
||||||
|
This function should specify the combinatorial logic behavior.
|
||||||
|
:func:`always_comb()` returns a generator that is sensitive to all
|
||||||
|
inputs, and that will run the function whenever an input changes.
|
||||||
|
|
||||||
|
For example, suppose that we have a mux module described as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def mux(z, a, b, sel):
|
||||||
|
""" Multiplexer.
|
||||||
|
|
||||||
|
z -- mux output
|
||||||
|
a, b -- data inputs
|
||||||
|
sel -- control input
|
||||||
|
|
||||||
|
"""
|
||||||
|
def logic()
|
||||||
|
while 1:
|
||||||
|
yield a, b, sel
|
||||||
|
if sel == 1:
|
||||||
|
z.next = a
|
||||||
|
else:
|
||||||
|
z.next = b
|
||||||
|
mux_logic = logic()
|
||||||
|
return mux_logic
|
||||||
|
|
||||||
|
Using :func:`always_comb()`, we can describe it as follows instead:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def mux(z, a, b, sel):
|
||||||
|
""" Multiplexer.
|
||||||
|
|
||||||
|
z -- mux output
|
||||||
|
a, b -- data inputs
|
||||||
|
sel -- control input
|
||||||
|
|
||||||
|
"""
|
||||||
|
def logic()
|
||||||
|
if sel == 1:
|
||||||
|
z.next = a
|
||||||
|
else:
|
||||||
|
z.next = b
|
||||||
|
mux_logic = always_comb(logic)
|
||||||
|
return mux_logic
|
||||||
|
|
||||||
|
Note that in the first version, the sensitivity list is at the beginning
|
||||||
|
of the generator function code. This is traditionally done in
|
||||||
|
synthesizable RTL style modeling. However, the semantics of this style
|
||||||
|
are not entirely correct: at the start of the simulation, the
|
||||||
|
combinatorial output will not reflect the initial state of the inputs.
|
||||||
|
:func:`always_comb()` solves this by putting the sensitivity list at the
|
||||||
|
end of the code.
|
||||||
|
|
||||||
|
Inferring the list of instances
|
||||||
|
===============================
|
||||||
|
|
||||||
|
In MyHDL, the instances defined in a top level function need to be
|
||||||
|
returned explicitly. The following is a schematic example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def top(...):
|
||||||
|
...
|
||||||
|
instance_1 = module_1(...)
|
||||||
|
instance_2 = module_2(...)
|
||||||
|
...
|
||||||
|
instance_n = module_n(...)
|
||||||
|
...
|
||||||
|
return instance_1, instance_2, ... , instance_n
|
||||||
|
|
||||||
|
It may be convenient to assemble the list of instances automatically,
|
||||||
|
especially if there are many instances. For this purpose, MyHDL 0.3
|
||||||
|
provides the function :func:`instances()`. It is used as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from myhdl import instances
|
||||||
|
|
||||||
|
def top(...):
|
||||||
|
...
|
||||||
|
instance_1 = module_1(...)
|
||||||
|
instance_2 = module_2(...)
|
||||||
|
...
|
||||||
|
instance_n = module_n(...)
|
||||||
|
...
|
||||||
|
return instances()
|
||||||
|
|
||||||
|
Function :func:`instances()` uses introspection to inspect the type of
|
||||||
|
the local variables defined by the calling function. All variables that
|
||||||
|
comply with the definition of an instance are assembled in a list, and
|
||||||
|
that list is returned.
|
||||||
|
|
||||||
|
Inferring the list of processes
|
||||||
|
===============================
|
||||||
|
|
||||||
|
In addition to instances, a top level function may also define local
|
||||||
|
generators functions, which I will call *processes* because of the
|
||||||
|
analogy with VHDL. Like instances, processes need to be returned
|
||||||
|
explicitly, with the qualification that they have to be called first to
|
||||||
|
turn them into generators. The following is a schematic example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def top(...):
|
||||||
|
...
|
||||||
|
def process_1():
|
||||||
|
...
|
||||||
|
def process_2():
|
||||||
|
...
|
||||||
|
...
|
||||||
|
def process_n():
|
||||||
|
...
|
||||||
|
...
|
||||||
|
return process_1(), process_2(), ..., process_n()
|
||||||
|
|
||||||
|
As for instances, it may be more convenient to assemble the list of
|
||||||
|
processes automatically. One option is to turn each process into an
|
||||||
|
instance by calling it and assigning the returned generator to a local
|
||||||
|
variable. Those instances will then be found by the :func:`instances()`
|
||||||
|
function described in
|
||||||
|
Section \ `4 <#inferring-the-list-of-instances>`__.
|
||||||
|
|
||||||
|
Another option is to use the function :func:`processes()` provided by
|
||||||
|
MyHDL 0.3. This function uses introspection to find the processes, calls
|
||||||
|
each of them, and assembles the returned generators into a list. It can
|
||||||
|
be used as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from myhdl import processes
|
||||||
|
|
||||||
|
def top(...):
|
||||||
|
...
|
||||||
|
def process_1():
|
||||||
|
...
|
||||||
|
def process_2():
|
||||||
|
...
|
||||||
|
...
|
||||||
|
def process_n():
|
||||||
|
...
|
||||||
|
...
|
||||||
|
return processes()
|
||||||
|
|
||||||
|
To conclude, a top level function with both instances and processes can
|
||||||
|
use the following idiomatic code to return all of them:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
return instances(), processes()
|
||||||
|
|
||||||
|
Class :class:`intbv` enhancements
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Class :class:`intbv` has been enhanced with new features.
|
||||||
|
|
||||||
|
It is now possible to leave the left index of a slicing operation
|
||||||
|
unspecified. The meaning is to access “all” higher order bits. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> from myhdl import intbv
|
||||||
|
>>> n = intbv()
|
||||||
|
>>> hex(n)
|
||||||
|
'0x0'
|
||||||
|
>>> n[:] = 0xde
|
||||||
|
>>> hex(n)
|
||||||
|
'0xde'
|
||||||
|
>>> n[:8] = 0xfa
|
||||||
|
>>> hex(n)
|
||||||
|
'0xfade'
|
||||||
|
>>> n[8:] = 0xb4
|
||||||
|
>>> hex(n)
|
||||||
|
'0xfab4'
|
||||||
|
|
||||||
|
:class:`intbv` objects now have ``min`` and ``max`` attributes that can
|
||||||
|
be specified at construction time. The meaning is that only values
|
||||||
|
within ``range(min, max)`` are permitted. The default value for these
|
||||||
|
attributes is ``None``, meaning “infinite”. For example (traceback
|
||||||
|
output shortened for clarity):
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> n = intbv(min=-17, max=53)
|
||||||
|
>>> n
|
||||||
|
intbv(0)
|
||||||
|
>>> n.min
|
||||||
|
-17
|
||||||
|
>>> n.max
|
||||||
|
53
|
||||||
|
>>> n[:] = 28
|
||||||
|
>>> n
|
||||||
|
intbv(28)
|
||||||
|
>>> n[:] = -18
|
||||||
|
Traceback (most recent call last):
|
||||||
|
....
|
||||||
|
ValueError: intbv value -18 < minimum -17
|
||||||
|
>>> n[:] = 53
|
||||||
|
Traceback (most recent call last):
|
||||||
|
....
|
||||||
|
ValueError: intbv value 53 >= maximum 53
|
||||||
|
|
||||||
|
When a slice is taken from an :class:`intbv` object, the return value is
|
||||||
|
a new :class:`intbv` object with a defined bit width. As in Verilog, the
|
||||||
|
value of the new :class:`intbv` object is always positive, regardless of
|
||||||
|
the sign of the original value. In addition, the ``min`` and ``max``
|
||||||
|
attributes are set implicitly:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> v = intbv()[6:]
|
||||||
|
>>> v
|
||||||
|
intbv(0)
|
||||||
|
>>> v.min
|
||||||
|
0
|
||||||
|
>>> v.max
|
||||||
|
64
|
||||||
|
|
||||||
|
Lastly, a small change was implemented with regard to binary operations.
|
||||||
|
In previous versions, both numeric and bit-wise operations always
|
||||||
|
returned a new :class:`intbv` object, even in mixed-mode operations with
|
||||||
|
:class:`int` objects. This has changed: numeric operations return an
|
||||||
|
:class:`int`, and bitwise operations return a :class:`intbv`. In this
|
||||||
|
way, the return value corresponds better to the nature of the operation.
|
||||||
|
|
||||||
|
Function :func:`concat()`
|
||||||
|
==========================
|
||||||
|
|
||||||
|
In previous versions, the :class:`intbv` class provided a method. This
|
||||||
|
method is no longer available. Instead, there is now a :func:`concat()`
|
||||||
|
function that supports a much broader range of objects.
|
||||||
|
|
||||||
|
A function is more natural because MyHDL objects of various types can be
|
||||||
|
concatenated: :class:`intbv` objects with a defined bit width,
|
||||||
|
:class:`bool` objects, the corresponding signal objects, and bit
|
||||||
|
strings. All these objects have a defined bit width. Moreover, the first
|
||||||
|
argument doesn’t need to have a defined bit width. It can also be an
|
||||||
|
unsized :class:`intbv`, an :class:`int`, a :class:`long`, or a
|
||||||
|
corresponding signal object. Function :func:`concat()` returns an
|
||||||
|
:class:`intbv` object.
|
||||||
|
|
||||||
|
Python 2.3 support
|
||||||
|
==================
|
||||||
|
|
||||||
|
Python 2.3 was released on July 29, 2003, and as of this writing, it is
|
||||||
|
the latest stable Python release. MyHDL 0.3 works with both Python 2.2
|
||||||
|
and Python 2.3. In good Python tradition, MyHDL code developed with
|
||||||
|
Python 2.2 should run without changes or problems in Python 2.3.
|
||||||
|
|
||||||
|
In general, I am not that keen on early upgrading. However, as it
|
||||||
|
happens, the evolution of Python enables features that are really
|
||||||
|
important or even crucial to MyHDL. Python 2.2 generators are the best
|
||||||
|
example: they are the cornerstone of MyHDL. But Python 2.3 also has
|
||||||
|
significant benefits, which I will summarize below.
|
||||||
|
|
||||||
|
First, generators and the ``yield`` statement are a default Python 2.3
|
||||||
|
feature. This means that statements are no longer required.
|
||||||
|
|
||||||
|
Second, Python 2.3 has a :class:`bool` type, which is implemented as a
|
||||||
|
subtype of :class:`int`. For general Python use, the implications are
|
||||||
|
rather limited - the main difference is that logical result values will
|
||||||
|
print as ``False`` and ``True`` instead of ``0`` and ``1``. However, in
|
||||||
|
MyHDL, I can use the :class:`bool` type to infer a bit width. If a
|
||||||
|
:class:`Signal` is constructed with a :class:`bool` value, it is a
|
||||||
|
single bit :class:`Signal`. One application is waveform viewing as in
|
||||||
|
Section \ `1 <#vcd-output-for-waveform-viewing>`__ In the waveform, note
|
||||||
|
how single bit signals are displayed as level changes. With Python 2.2,
|
||||||
|
the waveforms of these signals would only show value changes, which is
|
||||||
|
not as clear for single bits.
|
||||||
|
|
||||||
|
Finally, Python 2.3 is significantly faster. MyHDL code runs 25–35%
|
||||||
|
faster in Python 2.3. This is a very nice speedup compared to the small
|
||||||
|
burden of a straightforward upgrade.
|
||||||
|
|
||||||
|
Python is a very stable language, so upgrading to Python 2.3 is
|
||||||
|
virtually risk free. Given the additional benefits, I recommend
|
||||||
|
MyHDL users to do so as soon as possible. For the next major
|
||||||
|
MyHDLrelease, the new features will become required and only Python 2.3
|
||||||
|
(and higher) will be supported.
|
||||||
|
|
||||||
|
.. |image| image:: ../manual/tbfsm.png
|
791
doc/source/whatsnew/0.4.rst
Normal file
@ -0,0 +1,791 @@
|
|||||||
|
=======================================
|
||||||
|
New in MyHDL 0.4: Conversion to Verilog
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
:Author: Jan Decaluwe
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
MyHDL 0.4 supports the automatic conversion of a subset of MyHDL code to
|
||||||
|
synthesizable Verilog code. This feature provides a direct path from
|
||||||
|
Python to an FPGA or ASIC implementation.
|
||||||
|
|
||||||
|
MyHDL aims to be a complete design language, for tasks such as high
|
||||||
|
level modeling and verification, but also for implementation. However,
|
||||||
|
prior to 0.4 a user had to translate MyHDL code manually to Verilog or
|
||||||
|
VHDL. Needless to say, this was inconvenient. With MyHDL0.4, this manual
|
||||||
|
step is no longer necessary.
|
||||||
|
|
||||||
|
Solution description
|
||||||
|
====================
|
||||||
|
|
||||||
|
The solution works as follows. The hardware description should be
|
||||||
|
modeled in MyHDL style, and satisfy certain constraints that are typical
|
||||||
|
for implementation-oriented hardware modeling. Subsequently, such a
|
||||||
|
design is converted to an equivalent model in the Verilog language,
|
||||||
|
using the function :func:`toVerilog` from the MyHDLlibrary. Finally, a
|
||||||
|
third-party *synthesis tool* is used to convert the Verilog design to a
|
||||||
|
gate implementation for an ASIC or FPGA. There are a number of Verilog
|
||||||
|
synthesis tools available, varying in price, capabilities, and target
|
||||||
|
implementation technology.
|
||||||
|
|
||||||
|
The conversion does not start from source files, but from a design that
|
||||||
|
has been *elaborated* by the Python interpreter. The converter uses the
|
||||||
|
Python profiler to track the interpreter’s operation and to infer the
|
||||||
|
design structure and name spaces. It then selectively compiles pieces of
|
||||||
|
source code for additional analysis and for conversion. This is done
|
||||||
|
using the Python compiler package.
|
||||||
|
|
||||||
|
Features
|
||||||
|
========
|
||||||
|
|
||||||
|
The design is converted after elaboration
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
*Elaboration* refers to the initial processing of a hardware description
|
||||||
|
to achieve a representation of a design instance that is ready for
|
||||||
|
simulation or synthesis. In particular, structural parameters and
|
||||||
|
constructs are processed in this step. In MyHDL, the Python interpreter
|
||||||
|
itself is used for elaboration. A :class:`Simulation` object is
|
||||||
|
constructed with elaborated design instances as arguments. Likewise, the
|
||||||
|
Verilog conversion works on an elaborated design instance. The Python
|
||||||
|
interpreter is thus used as much as possible.
|
||||||
|
|
||||||
|
The structural description can be arbitrarily complex and hierarchical
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
As the conversion works on an elaborated design instance, any modeling
|
||||||
|
constraints only apply to the leaf elements of the design structure,
|
||||||
|
that is, the co-operating generators. In other words, there are no
|
||||||
|
restrictions on the description of the design structure: Python’s full
|
||||||
|
power can be used for that purpose. Also, the design hierarchy can be
|
||||||
|
arbitrarily deep.
|
||||||
|
|
||||||
|
Generators are mapped to Verilog always or initial blocks
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
The converter analyzes the code of each generator and maps it to a
|
||||||
|
Verilog ``always`` blocks if possible, and to an ``initial`` block
|
||||||
|
otherwise. The converted Verilog design will be a flat “net list of
|
||||||
|
blocks”.
|
||||||
|
|
||||||
|
The Verilog module interface is inferred from signal usage
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
In MyHDL, the input or output direction of interface signals is not
|
||||||
|
explicitly declared. The converter investigates signal usage in the
|
||||||
|
design hierarchy to infer whether a signal is used as input, output, or
|
||||||
|
as an internal signal. Internal signals are given a hierarchical name in
|
||||||
|
the Verilog output.
|
||||||
|
|
||||||
|
Function calls are mapped to a unique Verilog function or task call
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
The converter analyzes function calls and function code to see if they
|
||||||
|
should be mapped to Verilog functions or to tasks. Python functions are
|
||||||
|
much more powerful than Verilog subprograms; for example, they are
|
||||||
|
inherently generic, and they can be called with named association. To
|
||||||
|
support this power in Verilog, a unique Verilog function or task is
|
||||||
|
generated per Python function call.
|
||||||
|
|
||||||
|
If-then-else structures may be mapped to Verilog case statements
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
Python does not provide a case statement. However, the converter
|
||||||
|
recognizes if-then-else structures in which a variable is sequentially
|
||||||
|
compared to items of an enumeration type, and maps such a structure to a
|
||||||
|
Verilog case statement with the appropriate synthesis attributes.
|
||||||
|
|
||||||
|
Choice of encoding schemes for enumeration types
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
The :func:`enum` function in MyHDL returns an enumeration type. This
|
||||||
|
function takes an additional parameter ``encoding`` that specifies the
|
||||||
|
desired encoding in the implementation: binary, one hot, or one cold.
|
||||||
|
The Verilog converter generates the appropriate code.
|
||||||
|
|
||||||
|
The convertible subset
|
||||||
|
======================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Unsurprisingly, not all MyHDL code can be converted to Verilog. In fact,
|
||||||
|
there are very important restrictions. As the goal of the conversion
|
||||||
|
functionality is implementation, this should not be a big issue: anyone
|
||||||
|
familiar with synthesis is used to similar restrictions in the
|
||||||
|
*synthesizable subset* of Verilog and VHDL. The converter attempts to
|
||||||
|
issue clear error messages when it encounters a construct that cannot be
|
||||||
|
converted.
|
||||||
|
|
||||||
|
In practice, the synthesizable subset usually refers to RTL synthesis,
|
||||||
|
which is by far the most popular type of synthesis today. There are
|
||||||
|
industry standards that define the RTL synthesis subset. However, those
|
||||||
|
were not used as a model for the restrictions of the MyHDL converter,
|
||||||
|
but as a minimal starting point. On that basis, whenever it was judged
|
||||||
|
easy or useful to support an additional feature, this was done. For
|
||||||
|
example, it is actually easier to convert :keyword:`while` loops than
|
||||||
|
:keyword:`for` loops even though they are not RTL-synthesizable. As
|
||||||
|
another example, :keyword:`print` is supported because it’s so useful
|
||||||
|
for debugging, even though it’s not synthesizable. In summary, the
|
||||||
|
convertible subset is a superset of the standard RTL synthesis subset,
|
||||||
|
and supports synthesis tools with more advanced capabilities, such as
|
||||||
|
behavioral synthesis.
|
||||||
|
|
||||||
|
Recall that any restrictions only apply to the design post elaboration.
|
||||||
|
In practice, this means that they apply only to the code of the
|
||||||
|
generators, that are the leaf functional blocks in a MyHDL design.
|
||||||
|
|
||||||
|
Coding style
|
||||||
|
------------
|
||||||
|
|
||||||
|
A natural restriction on convertible code is that it should be written
|
||||||
|
in MyHDL style: cooperating generators, communicating through signals,
|
||||||
|
and with ``yield`` statements specifying wait points and resume
|
||||||
|
conditions. Supported resume conditions are a signal edge, a signal
|
||||||
|
change, or a tuple of such conditions.
|
||||||
|
|
||||||
|
Supported types
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The most important restriction regards object types. Verilog is an
|
||||||
|
almost typeless language, while Python is strongly (albeit dynamically)
|
||||||
|
typed. The converter has to infer the types of names used in the code,
|
||||||
|
and map those names to Verilog variables.
|
||||||
|
|
||||||
|
Only a limited amount of types can be converted. Python :class:`int` and
|
||||||
|
:class:`long` objects are mapped to Verilog integers. All other
|
||||||
|
supported types are mapped to Verilog regs (or wires), and therefore
|
||||||
|
need to have a defined bit width. The supported types are the Python
|
||||||
|
:class:`bool` type, the MyHDL :class:`intbv` type, and MyHDL enumeration
|
||||||
|
types returned by function :func:`enum`. The latter objects can also be
|
||||||
|
used as the base object of a :class:`Signal`.
|
||||||
|
|
||||||
|
:class:`intbv` objects must be constructed so that a bit width can be
|
||||||
|
inferred. This can be done by specifying minimum and maximum values,
|
||||||
|
e.g. as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
index = intbv(0, min=0, max=2**N)
|
||||||
|
|
||||||
|
Alternatively, a slice can be taken from an :class:`intbv` object as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
index = intbv(0)[N:]
|
||||||
|
|
||||||
|
Such as slice returns a new :class:`intbv` object, with minimum value
|
||||||
|
``0`` , and maximum value ``2**N``.
|
||||||
|
|
||||||
|
Supported statements
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The following is a list of the statements that are supported by the
|
||||||
|
Verilog converter, possibly qualified with restrictions or usage notes.
|
||||||
|
|
||||||
|
The :keyword:`break` statement.
|
||||||
|
The :keyword:`continue` statement.
|
||||||
|
The :keyword:`def` statement.
|
||||||
|
The :keyword:`for` statement.
|
||||||
|
The only supported iteration scheme is iterating through sequences
|
||||||
|
of integers returned by built-in function :func:`range` or
|
||||||
|
MyHDLfunction :func:`downrange`. The optional :keyword:`else` clause
|
||||||
|
is not supported.
|
||||||
|
|
||||||
|
The :keyword:`if` statement.
|
||||||
|
:keyword:`if`, :keyword:`elif`, and :keyword:`else` clauses are
|
||||||
|
fully supported.
|
||||||
|
|
||||||
|
The :keyword:`pass` statement.
|
||||||
|
The :keyword:`print` statement.
|
||||||
|
When printing an interpolated string, the format specifiers are
|
||||||
|
copied verbatim to the Verilog output. Printing to a file (with
|
||||||
|
syntax ``’>>’``) is not supported.
|
||||||
|
|
||||||
|
The :keyword:`raise` statement.
|
||||||
|
This statement is mapped to Verilog statements that end the
|
||||||
|
simulation with an error message.
|
||||||
|
|
||||||
|
The :keyword:`return` statement.
|
||||||
|
The :keyword:`yield` statement.
|
||||||
|
The yielded expression can be a signal, a signal edge as specified
|
||||||
|
by MyHDL functions :func:`posedge` or :func:`negedge`, or a tuple of
|
||||||
|
signals and edge specifications.
|
||||||
|
|
||||||
|
The :keyword:`while` statement.
|
||||||
|
The optional :keyword:`else` clause is not supported.
|
||||||
|
|
||||||
|
Methodology notes
|
||||||
|
=================
|
||||||
|
|
||||||
|
Simulation
|
||||||
|
----------
|
||||||
|
|
||||||
|
In the Python philosophy, the run-time rules. The Python compiler
|
||||||
|
doesn’t attempt to detect a lot of errors beyond syntax errors, which
|
||||||
|
given Python’s ultra-dynamic nature would be an almost impossible task
|
||||||
|
anyway. To verify a Python program, one should run it, preferably using
|
||||||
|
unit testing to verify each feature.
|
||||||
|
|
||||||
|
The same philosophy should be used when converting a MyHDL description
|
||||||
|
to Verilog: make sure the simulation runs fine first. Although the
|
||||||
|
converter checks many things and attempts to issue clear error messages,
|
||||||
|
there is no guarantee that it does a meaningful job unless the
|
||||||
|
simulation runs fine.
|
||||||
|
|
||||||
|
Conversion output verification
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
It is always prudent to verify the converted Verilog output. To make
|
||||||
|
this task easier, the converter also generates a test bench that makes
|
||||||
|
it possible to simulate the Verilog design using the Verilog
|
||||||
|
co-simulation interface. This permits to verify the Verilog code with
|
||||||
|
the same test bench used for the MyHDL code. This is also how the
|
||||||
|
Verilog converter development is being verified.
|
||||||
|
|
||||||
|
Assignment issues
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Name assignment in Python
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Name assignment in Python is a different concept than in many other
|
||||||
|
languages. This point is very important for effective modeling in
|
||||||
|
Python, and even more so for synthesizable MyHDL code. Therefore, the
|
||||||
|
issues are discussed here explicitly.
|
||||||
|
|
||||||
|
Consider the following name assignments:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a = 4
|
||||||
|
a = ``a string''
|
||||||
|
a = False
|
||||||
|
|
||||||
|
In many languages, the meaning would be that an existing variable ``a``
|
||||||
|
gets a number of different values. In Python, such a concept of a
|
||||||
|
variable doesn’t exist. Instead, assignment merely creates a new binding
|
||||||
|
of a name to a certain object, that replaces any previous binding. So in
|
||||||
|
the example, the name ``a`` is bound a number of different objects in
|
||||||
|
sequence.
|
||||||
|
|
||||||
|
The Verilog converter has to investigate name assignment and usage in
|
||||||
|
MyHDL code, and to map names to Verilog variables. To achieve that, it
|
||||||
|
tries to infer the type and possibly the bit width of each expression
|
||||||
|
that is assigned to a name.
|
||||||
|
|
||||||
|
Multiple assignments to the same name can be supported if it can be
|
||||||
|
determined that a consistent type and bit width is being used in the
|
||||||
|
assignments. This can be done for boolean expressions, numeric
|
||||||
|
expressions, and enumeration type literals. In Verilog, the
|
||||||
|
corresponding name is mapped to a single bit ``reg``, an ``integer``, or
|
||||||
|
a ``reg`` with the appropriate width, respectively.
|
||||||
|
|
||||||
|
In other cases, a single assignment should be used when an object is
|
||||||
|
created. Subsequent value changes are then achieved by modification of
|
||||||
|
an existing object. This technique should be used for :class:`Signal`
|
||||||
|
and :class:`intbv` objects.
|
||||||
|
|
||||||
|
Signal assignment
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Signal assignment in MyHDL is implemented using attribute assignment to
|
||||||
|
attribute ``next``. Value changes are thus modeled by modification of
|
||||||
|
the existing object. The converter investigates the :class:`Signal`
|
||||||
|
object to infer the type and bit width of the corresponding Verilog
|
||||||
|
variable.
|
||||||
|
|
||||||
|
:class:`intbv` objects
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Type :class:`intbv` is likely to be the workhorse for synthesizable
|
||||||
|
modeling in MyHDL. An :class:`intbv` instance behaves like a (mutable)
|
||||||
|
integer whose individual bits can be accessed and modified. Also, it is
|
||||||
|
possible to constrain its set of values. In addition to error checking,
|
||||||
|
this makes it possible to infer a bit width, which is required for
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
In Verilog, an :class:`intbv` instance will be mapped to a ``reg`` with
|
||||||
|
an appropriate width. As noted before, it is not possible to modify its
|
||||||
|
value using name assignment. In the following, we will show how it can
|
||||||
|
be done instead. Consider:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a = intbv(0)[8:]
|
||||||
|
|
||||||
|
This is an :class:`intbv` object with initial value ``0`` and bit width
|
||||||
|
8. The change its value to ``5``, we can use slice assignment:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a[8:] = 5
|
||||||
|
|
||||||
|
The same can be achieved by leaving the bit width unspecified, which has
|
||||||
|
the meaning to change “all” bits:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a[:] = 5
|
||||||
|
|
||||||
|
Often the new value will depend on the old one. For example, to
|
||||||
|
increment an :class:`intbv` with the technique above:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a[:] = a + 1
|
||||||
|
|
||||||
|
Python also provides *augmented* assignment operators, which can be used
|
||||||
|
to implement in-place operations. These are supported on :class:`intbv`
|
||||||
|
objects and by the converter, so that the increment can also be done as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
a += 1
|
||||||
|
|
||||||
|
Converter usage
|
||||||
|
===============
|
||||||
|
|
||||||
|
We will demonstrate the conversion process by showing some examples.
|
||||||
|
|
||||||
|
A small design with a single generator
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Consider the following MyHDL code for an incrementer module:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def inc(count, enable, clock, reset, n):
|
||||||
|
""" Incrementer with enable.
|
||||||
|
|
||||||
|
count -- output
|
||||||
|
enable -- control input, increment when 1
|
||||||
|
clock -- clock input
|
||||||
|
reset -- asynchronous reset input
|
||||||
|
n -- counter max value
|
||||||
|
"""
|
||||||
|
def incProcess():
|
||||||
|
while 1:
|
||||||
|
yield posedge(clock), negedge(reset)
|
||||||
|
if reset == ACTIVE_LOW:
|
||||||
|
count.next = 0
|
||||||
|
else:
|
||||||
|
if enable:
|
||||||
|
count.next = (count + 1) % n
|
||||||
|
return incProcess()
|
||||||
|
|
||||||
|
In Verilog terminology, function :func:`inc` corresponds to a module,
|
||||||
|
while generator function :func:`incProcess` roughly corresponds to an
|
||||||
|
always block.
|
||||||
|
|
||||||
|
Normally, to simulate the design, we would “elaborate” an instance as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
m = 8
|
||||||
|
n = 2 ** m
|
||||||
|
|
||||||
|
count = Signal(intbv(0)[m:])
|
||||||
|
enable = Signal(bool(0))
|
||||||
|
clock, reset = [Signal(bool()) for i in range(2)]
|
||||||
|
|
||||||
|
inc_inst = inc(count, enable, clock, reset, n=n)
|
||||||
|
|
||||||
|
``incinst`` is an elaborated design instance that can be simulated. To
|
||||||
|
convert it to Verilog, we change the last line as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
inc_inst = toVerilog(inc, count, enable, clock, reset, n=n)
|
||||||
|
|
||||||
|
Again, this creates an instance that can be simulated, but as a side
|
||||||
|
effect, it also generates an equivalent Verilog module in file . The
|
||||||
|
Verilog code looks as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
module inc_inst (
|
||||||
|
count,
|
||||||
|
enable,
|
||||||
|
clock,
|
||||||
|
reset
|
||||||
|
);
|
||||||
|
|
||||||
|
output [7:0] count;
|
||||||
|
reg [7:0] count;
|
||||||
|
input enable;
|
||||||
|
input clock;
|
||||||
|
input reset;
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
|
||||||
|
if ((reset == 0)) begin
|
||||||
|
count <= 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (enable) begin
|
||||||
|
count <= ((count + 1) % 256);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
You can see the module interface and the always block, as expected from
|
||||||
|
the MyHDL design.
|
||||||
|
|
||||||
|
Converting a generator directly
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
It is also possible to convert a generator directly. For example,
|
||||||
|
consider the following generator function:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def bin2gray(B, G, width):
|
||||||
|
""" Gray encoder.
|
||||||
|
|
||||||
|
B -- input intbv signal, binary encoded
|
||||||
|
G -- output intbv signal, gray encoded
|
||||||
|
width -- bit width
|
||||||
|
"""
|
||||||
|
Bext = intbv(0)[width+1:]
|
||||||
|
while 1:
|
||||||
|
yield B
|
||||||
|
Bext[:] = B
|
||||||
|
for i in range(width):
|
||||||
|
G.next[i] = Bext[i+1] ^ Bext[i]
|
||||||
|
|
||||||
|
As before, you can create an instance and convert to Verilog as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
width = 8
|
||||||
|
|
||||||
|
B = Signal(intbv(0)[width:])
|
||||||
|
G = Signal(intbv(0)[width:])
|
||||||
|
|
||||||
|
bin2gray_inst = toVerilog(bin2gray, B, G, width)
|
||||||
|
|
||||||
|
|
||||||
|
The generated Verilog code looks as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
module bin2gray_inst (
|
||||||
|
B,
|
||||||
|
G
|
||||||
|
);
|
||||||
|
|
||||||
|
input [7:0] B;
|
||||||
|
output [7:0] G;
|
||||||
|
reg [7:0] G;
|
||||||
|
|
||||||
|
always @(B) begin: _MYHDL1_BLOCK
|
||||||
|
integer i;
|
||||||
|
reg [9-1:0] Bext;
|
||||||
|
Bext[9-1:0] = B;
|
||||||
|
for (i=0; i<8; i=i+1) begin
|
||||||
|
G[i] <= (Bext[(i + 1)] ^ Bext[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
A hierarchical design
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The hierarchy of convertible designs can be arbitrarily deep.
|
||||||
|
|
||||||
|
For example, suppose we want to design an incrementer with Gray code
|
||||||
|
output. Using the designs from previous sections, we can proceed as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def GrayInc(graycnt, enable, clock, reset, width):
|
||||||
|
|
||||||
|
bincnt = Signal(intbv()[width:])
|
||||||
|
|
||||||
|
INC_1 = inc(bincnt, enable, clock, reset, n=2**width)
|
||||||
|
BIN2GRAY_1 = bin2gray(B=bincnt, G=graycnt, width=width)
|
||||||
|
|
||||||
|
return INC_1, BIN2GRAY_1
|
||||||
|
|
||||||
|
According to Gray code properties, only a single bit will change in
|
||||||
|
consecutive values. However, as the ``bin2gray`` module is
|
||||||
|
combinatorial, the output bits may have transient glitches, which may
|
||||||
|
not be desirable. To solve this, let’s create an additional level of
|
||||||
|
hierarchy and add an output register to the design. (This will create an
|
||||||
|
additional latency of a clock cycle, which may not be acceptable, but we
|
||||||
|
will ignore that here.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
def GrayIncReg(graycnt, enable, clock, reset, width):
|
||||||
|
|
||||||
|
graycnt_comb = Signal(intbv()[width:])
|
||||||
|
|
||||||
|
GRAY_INC_1 = GrayInc(graycnt_comb, enable, clock, reset, width)
|
||||||
|
|
||||||
|
def reg():
|
||||||
|
while 1:
|
||||||
|
yield posedge(clock)
|
||||||
|
graycnt.next = graycnt_comb
|
||||||
|
REG_1 = reg()
|
||||||
|
|
||||||
|
return GRAY_INC_1, REG_1
|
||||||
|
|
||||||
|
We can convert this hierarchical design as before:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
width = 8
|
||||||
|
graycnt = Signal(intbv()[width:])
|
||||||
|
enable, clock, reset = [Signal(bool()) for i in range(3)]
|
||||||
|
|
||||||
|
GRAY_INC_REG_1 = toVerilog(GrayIncReg, graycnt, enable, clock, reset, width)
|
||||||
|
|
||||||
|
The Verilog output code looks as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
module GRAY_INC_REG_1 (
|
||||||
|
graycnt,
|
||||||
|
enable,
|
||||||
|
clock,
|
||||||
|
reset
|
||||||
|
);
|
||||||
|
|
||||||
|
output [7:0] graycnt;
|
||||||
|
reg [7:0] graycnt;
|
||||||
|
input enable;
|
||||||
|
input clock;
|
||||||
|
input reset;
|
||||||
|
|
||||||
|
reg [7:0] graycnt_comb;
|
||||||
|
reg [7:0] _GRAY_INC_1_bincnt;
|
||||||
|
|
||||||
|
always @(posedge clock or negedge reset) begin: _MYHDL1_BLOCK
|
||||||
|
if ((reset == 0)) begin
|
||||||
|
_GRAY_INC_1_bincnt <= 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (enable) begin
|
||||||
|
_GRAY_INC_1_bincnt <= ((_GRAY_INC_1_bincnt + 1) % 256);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(_GRAY_INC_1_bincnt) begin: _MYHDL4_BLOCK
|
||||||
|
integer i;
|
||||||
|
reg [9-1:0] Bext;
|
||||||
|
Bext[9-1:0] = _GRAY_INC_1_bincnt;
|
||||||
|
for (i=0; i<8; i=i+1) begin
|
||||||
|
graycnt_comb[i] <= (Bext[(i + 1)] ^ Bext[i]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clock) begin: _MYHDL9_BLOCK
|
||||||
|
graycnt <= graycnt_comb;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
Note that the output is a flat “net list of blocks”, and that
|
||||||
|
hierarchical signal names are generated as necessary.
|
||||||
|
|
||||||
|
Optimizations for finite state machines
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
As often in hardware design, finite state machines deserve special
|
||||||
|
attention.
|
||||||
|
|
||||||
|
In Verilog and VHDL, finite state machines are typically described using
|
||||||
|
case statements. Python doesn’t have a case statement, but the converter
|
||||||
|
recognizes particular if-then-else structures and maps them to case
|
||||||
|
statements. This optimization occurs when a variable whose type is an
|
||||||
|
enumerated type is sequentially tested against enumeration items in an
|
||||||
|
if-then-else structure. Also, the appropriate synthesis pragmas for
|
||||||
|
efficient synthesis are generated in the Verilog code.
|
||||||
|
|
||||||
|
As a further optimization, function :func:`enum` was enhanced to support
|
||||||
|
alternative encoding schemes elegantly, using an additional parameter
|
||||||
|
``encoding``. For example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
t_State = enum('SEARCH', 'CONFIRM', 'SYNC', encoding='one_hot')
|
||||||
|
|
||||||
|
The default encoding is ``’binary’``; the other possibilities are
|
||||||
|
``’onehot’`` and ``’onecold’``. This parameter only affects the
|
||||||
|
conversion output, not the behavior of the type. The generated Verilog
|
||||||
|
code for case statements is optimized for an efficient implementation
|
||||||
|
according to the encoding. Note that in contrast, a Verilog designer has
|
||||||
|
to make nontrivial code changes to implement a different encoding
|
||||||
|
scheme.
|
||||||
|
|
||||||
|
As an example, consider the following finite state machine, whose state
|
||||||
|
variable uses the enumeration type defined above:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
FRAME_SIZE = 8
|
||||||
|
|
||||||
|
def FramerCtrl(SOF, state, syncFlag, clk, reset_n):
|
||||||
|
|
||||||
|
""" Framing control FSM.
|
||||||
|
|
||||||
|
SOF -- start-of-frame output bit
|
||||||
|
state -- FramerState output
|
||||||
|
syncFlag -- sync pattern found indication input
|
||||||
|
clk -- clock input
|
||||||
|
reset_n -- active low reset
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
index = intbv(0, min=0, max=8) # position in frame
|
||||||
|
while 1:
|
||||||
|
yield posedge(clk), negedge(reset_n)
|
||||||
|
if reset_n == ACTIVE_LOW:
|
||||||
|
SOF.next = 0
|
||||||
|
index[:] = 0
|
||||||
|
state.next = t_State.SEARCH
|
||||||
|
else:
|
||||||
|
SOF.next = 0
|
||||||
|
if state == t_State.SEARCH:
|
||||||
|
index[:] = 0
|
||||||
|
if syncFlag:
|
||||||
|
state.next = t_State.CONFIRM
|
||||||
|
elif state == t_State.CONFIRM:
|
||||||
|
if index == 0:
|
||||||
|
if syncFlag:
|
||||||
|
state.next = t_State.SYNC
|
||||||
|
else:
|
||||||
|
state.next = t_State.SEARCH
|
||||||
|
elif state == t_State.SYNC:
|
||||||
|
if index == 0:
|
||||||
|
if not syncFlag:
|
||||||
|
state.next = t_State.SEARCH
|
||||||
|
SOF.next = (index == FRAME_SIZE-1)
|
||||||
|
else:
|
||||||
|
raise ValueError("Undefined state")
|
||||||
|
index[:]= (index + 1) % FRAME_SIZE
|
||||||
|
|
||||||
|
The conversion is done as before:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
SOF = Signal(bool(0))
|
||||||
|
syncFlag = Signal(bool(0))
|
||||||
|
clk = Signal(bool(0))
|
||||||
|
reset_n = Signal(bool(1))
|
||||||
|
state = Signal(t_State.SEARCH)
|
||||||
|
framerctrl_inst = toVerilog(FramerCtrl, SOF, state, syncFlag, clk, reset_n)
|
||||||
|
|
||||||
|
The Verilog output looks as follows:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
module framerctrl_inst (
|
||||||
|
SOF,
|
||||||
|
state,
|
||||||
|
syncFlag,
|
||||||
|
clk,
|
||||||
|
reset_n
|
||||||
|
);
|
||||||
|
output SOF;
|
||||||
|
reg SOF;
|
||||||
|
output [2:0] state;
|
||||||
|
reg [2:0] state;
|
||||||
|
input syncFlag;
|
||||||
|
input clk;
|
||||||
|
input reset_n;
|
||||||
|
|
||||||
|
always @(posedge clk or negedge reset_n) begin: _MYHDL1_BLOCK
|
||||||
|
reg [3-1:0] index;
|
||||||
|
if ((reset_n == 0)) begin
|
||||||
|
SOF <= 0;
|
||||||
|
index[3-1:0] = 0;
|
||||||
|
state <= 3'b001;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
SOF <= 0;
|
||||||
|
// synthesis parallel_case full_case
|
||||||
|
casez (state)
|
||||||
|
3'b??1: begin
|
||||||
|
index[3-1:0] = 0;
|
||||||
|
if (syncFlag) begin
|
||||||
|
state <= 3'b010;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
3'b?1?: begin
|
||||||
|
if ((index == 0)) begin
|
||||||
|
if (syncFlag) begin
|
||||||
|
state <= 3'b100;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
state <= 3'b001;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
3'b1??: begin
|
||||||
|
if ((index == 0)) begin
|
||||||
|
if ((!syncFlag)) begin
|
||||||
|
state <= 3'b001;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
SOF <= (index == (8 - 1));
|
||||||
|
end
|
||||||
|
default: begin
|
||||||
|
$display("Verilog: ValueError(Undefined state)");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
index[3-1:0] = ((index + 1) % 8);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
Known issues
|
||||||
|
============
|
||||||
|
|
||||||
|
Negative values of :class:`intbv` instances are not supported.
|
||||||
|
The :class:`intbv` class is quite capable of representing negative
|
||||||
|
values. However, the ``signed`` type support in Verilog is
|
||||||
|
relatively recent and mapping to it may be tricky. In my judgment,
|
||||||
|
this was not the most urgent requirement, so I decided to leave this
|
||||||
|
for later.
|
||||||
|
|
||||||
|
Verilog integers are 32 bit wide
|
||||||
|
Usually, Verilog integers are 32 bit wide. In contrast, Python is
|
||||||
|
moving toward integers with undefined width. Python :class:`int` and
|
||||||
|
:class:`long` variables are mapped to Verilog integers; so for
|
||||||
|
values wider than 32 bit this mapping is incorrect.
|
||||||
|
|
||||||
|
Synthesis pragmas are specified as Verilog comments.
|
||||||
|
The recommended way to specify synthesis pragmas in Verilog is
|
||||||
|
through attribute lists. However, my Verilog simulator (Icarus)
|
||||||
|
doesn’t support them for ``case`` statements (to specify
|
||||||
|
``parallelcase`` and ``fullcase`` pragmas). Therefore, I still used
|
||||||
|
the old but deprecated method of synthesis pragmas in Verilog
|
||||||
|
comments.
|
||||||
|
|
||||||
|
Inconsistent place of the sensitivity list inferred from ``alwayscomb``.
|
||||||
|
The semantics of ``alwayscomb``, both in Verilog and MyHDL, is to
|
||||||
|
have an implicit sensitivity list at the end of the code. However,
|
||||||
|
this may not be synthesizable. Therefore, the inferred sensitivity
|
||||||
|
list is put at the top of the corresponding ``always`` block. This
|
||||||
|
may cause inconsistent behavior at the start of the simulation. The
|
||||||
|
workaround is to create events at time 0.
|
||||||
|
|
||||||
|
Non-blocking assignments to task arguments don’t work.
|
||||||
|
I didn’t get non-blocking (signal) assignments to task arguments to
|
||||||
|
work. I don’t know yet whether the issue is my own, a Verilog issue,
|
||||||
|
or an issue with my Verilog simulator Icarus. I’ll need to check
|
||||||
|
this further.
|
426
olddoc/Makefile
@ -1,426 +0,0 @@
|
|||||||
# Makefile for Python documentation
|
|
||||||
# ---------------------------------
|
|
||||||
#
|
|
||||||
# See also the README file.
|
|
||||||
#
|
|
||||||
# This is a bit of a mess. The documents are identified by short names:
|
|
||||||
# api -- Python/C API Reference Manual
|
|
||||||
# doc -- Documenting Python
|
|
||||||
# ext -- Extending and Embedding the Python Interpreter
|
|
||||||
# lib -- Library Reference Manual
|
|
||||||
# mac -- Macintosh Library Modules
|
|
||||||
# ref -- Python Reference Manual
|
|
||||||
# tut -- Python Tutorial
|
|
||||||
# inst -- Installing Python Modules
|
|
||||||
# dist -- Distributing Python Modules
|
|
||||||
#
|
|
||||||
# The LaTeX sources for each of these documents are in subdirectories
|
|
||||||
# with the three-letter designations above as the directory names.
|
|
||||||
#
|
|
||||||
# The main target creates HTML for each of the documents. You can
|
|
||||||
# also do "make lib" (etc.) to create the HTML versions of individual
|
|
||||||
# documents.
|
|
||||||
#
|
|
||||||
# The document classes and styles are in the texinputs/ directory.
|
|
||||||
# These define a number of macros that are similar in name and intent
|
|
||||||
# as macros in Texinfo (e.g. \code{...} and \emph{...}), as well as a
|
|
||||||
# number of environments for formatting function and data definitions.
|
|
||||||
# Documentation for the macros is included in "Documenting Python"; see
|
|
||||||
# http://www.python.org/doc/current/doc/doc.html, or the sources for
|
|
||||||
# this document in the doc/ directory.
|
|
||||||
#
|
|
||||||
# Everything is processed by LaTeX. See the file `README' for more
|
|
||||||
# information on the tools needed for processing.
|
|
||||||
#
|
|
||||||
# There's a problem with generating the index which has been solved by
|
|
||||||
# a sed command applied to the index file. The shell script fix_hack
|
|
||||||
# does this (the Makefile takes care of calling it).
|
|
||||||
#
|
|
||||||
# Additional targets attempt to convert selected LaTeX sources to
|
|
||||||
# various other formats. These are generally site specific because
|
|
||||||
# the tools used are all but universal. These targets are:
|
|
||||||
#
|
|
||||||
# ps -- convert all documents from LaTeX to PostScript
|
|
||||||
# pdf -- convert all documents from LaTeX to the
|
|
||||||
# Portable Document Format
|
|
||||||
#
|
|
||||||
# See the README file for more information on these targets.
|
|
||||||
#
|
|
||||||
# The formatted output is located in subdirectories. For PDF and
|
|
||||||
# PostScript, look in the paper-$(PAPER)/ directory. For HTML, look in
|
|
||||||
# the html/ directory. If you want to fix the GNU info process, look
|
|
||||||
# in the info/ directory; please send patches to python-docs@python.org.
|
|
||||||
|
|
||||||
# This Makefile only includes information on how to perform builds; for
|
|
||||||
# dependency information, see Makefile.deps.
|
|
||||||
|
|
||||||
# Customization -- you *may* have to edit this
|
|
||||||
|
|
||||||
# You could set this to a4:
|
|
||||||
PAPER=a4
|
|
||||||
|
|
||||||
# Ideally, you shouldn't need to edit beyond this point
|
|
||||||
|
|
||||||
INFODIR= info
|
|
||||||
TOOLSDIR= tools
|
|
||||||
|
|
||||||
# This is the *documentation* release, and is used to construct the file
|
|
||||||
# names of the downloadable tarballs.
|
|
||||||
RELEASE=0.2
|
|
||||||
|
|
||||||
PYTHON= python
|
|
||||||
DVIPS= dvips -N0 -t $(PAPER)
|
|
||||||
|
|
||||||
MKDVI= $(PYTHON) ../tools/mkhowto --paper=$(PAPER) --dvi
|
|
||||||
MKHTML= $(PYTHON) tools/mkhowto --html --about html/myabout.dat \
|
|
||||||
--iconserver ../icons --favicon ../icons/pyfav.gif \
|
|
||||||
--address $(MYHDLDOCS) --up-link ../Overview.html \
|
|
||||||
--up-title "Overview" \
|
|
||||||
--dvips-safe
|
|
||||||
MKPDF= $(PYTHON) ../tools/mkhowto -l --paper=$(PAPER) --pdf
|
|
||||||
MKPS= $(PYTHON) ../tools/mkhowto --paper=$(PAPER) --ps
|
|
||||||
|
|
||||||
BUILDINDEX=$(TOOLSDIR)/buildindex.py
|
|
||||||
|
|
||||||
MYHDLDOCS="<i><a href=\"about.html\">About this document</a></i>"
|
|
||||||
HTMLBASE= file:`pwd`
|
|
||||||
|
|
||||||
# The emacs binary used to build the info docs. GNU Emacs 21 is required.
|
|
||||||
EMACS= emacs
|
|
||||||
|
|
||||||
# The end of this should reflect the major/minor version numbers of
|
|
||||||
# the release:
|
|
||||||
WHATSNEW=whatsnew04
|
|
||||||
|
|
||||||
# what's what
|
|
||||||
MANDVIFILES= paper-$(PAPER)/MyHDL.dvi
|
|
||||||
|
|
||||||
HOWTODVIFILES= paper-$(PAPER)/whatsnew03.dvi \
|
|
||||||
paper-$(PAPER)/whatsnew04.dvi
|
|
||||||
|
|
||||||
MANPDFFILES= paper-$(PAPER)/MyHDL.pdf
|
|
||||||
|
|
||||||
HOWTOPDFFILES= paper-$(PAPER)/whatsnew03.pdf \
|
|
||||||
paper-$(PAPER)/whatsnew04.pdf
|
|
||||||
|
|
||||||
MANPSFILES= paper-$(PAPER)/MyHDL.ps
|
|
||||||
|
|
||||||
HOWTOPSFILES= paper-$(PAPER)/whatsnew03.ps \
|
|
||||||
paper-$(PAPER)/whatsnew04.ps
|
|
||||||
|
|
||||||
DVIFILES= $(MANDVIFILES) $(HOWTODVIFILES)
|
|
||||||
PDFFILES= $(MANPDFFILES) $(HOWTOPDFFILES)
|
|
||||||
PSFILES= $(MANPSFILES) $(HOWTOPSFILES)
|
|
||||||
|
|
||||||
HTMLCSSFILES=html/manual/MyHDL.css \
|
|
||||||
html/whatsnew03/whatsnew03.css \
|
|
||||||
html/whatsnew04/whatsnew04.css
|
|
||||||
|
|
||||||
ALLCSSFILES=$(HTMLCSSFILES)
|
|
||||||
|
|
||||||
INDEXFILES=html/manual/MyHDL.html \
|
|
||||||
html/whatsnew03/whatsnew03.html \
|
|
||||||
html/whatsnew04/whatsnew04.html
|
|
||||||
|
|
||||||
ALLHTMLFILES=$(INDEXFILES)
|
|
||||||
|
|
||||||
COMMONPERL= perl/manual.perl perl/python.perl perl/l2hinit.perl
|
|
||||||
|
|
||||||
include Makefile.deps
|
|
||||||
|
|
||||||
# These must be declared phony since there
|
|
||||||
# are directories with matching names:
|
|
||||||
.PHONY: manual
|
|
||||||
.PHONY: html info
|
|
||||||
|
|
||||||
|
|
||||||
# Main target
|
|
||||||
default: all
|
|
||||||
all: html pdf
|
|
||||||
full: all ps
|
|
||||||
|
|
||||||
dvi: $(DVIFILES)
|
|
||||||
pdf: $(PDFFILES)
|
|
||||||
ps: $(PSFILES)
|
|
||||||
|
|
||||||
world: ps pdf html distfiles
|
|
||||||
|
|
||||||
|
|
||||||
# Rules to build PostScript and PDF formats
|
|
||||||
.SUFFIXES: .pdf .dvi .ps
|
|
||||||
|
|
||||||
#.dvi.ps:
|
|
||||||
# $(DVIPS) -o $@ $<
|
|
||||||
|
|
||||||
#.pdf.ps:
|
|
||||||
# pdf2ps $< $@
|
|
||||||
|
|
||||||
.pdf.ps:
|
|
||||||
xpdf $<
|
|
||||||
|
|
||||||
|
|
||||||
# Targets for each document:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MyHDL Manual
|
|
||||||
paper-$(PAPER)/MyHDL.dvi: $(MANUALFILES)
|
|
||||||
cd paper-$(PAPER) && $(MKDVI) ../manual/MyHDL.tex
|
|
||||||
|
|
||||||
paper-$(PAPER)/MyHDL.pdf: $(MANUALFILES)
|
|
||||||
cd paper-$(PAPER) && $(MKPDF) ../manual/MyHDL.tex
|
|
||||||
|
|
||||||
|
|
||||||
# What's new
|
|
||||||
# in 0.3
|
|
||||||
paper-$(PAPER)/whatsnew03.dvi: whatsnew03/whatsnew03.tex
|
|
||||||
cd paper-$(PAPER) && $(MKDVI) ../whatsnew03/whatsnew03.tex
|
|
||||||
|
|
||||||
paper-$(PAPER)/whatsnew03.pdf: whatsnew03/whatsnew03.tex
|
|
||||||
cd paper-$(PAPER) && $(MKPDF) ../whatsnew03/whatsnew03.tex
|
|
||||||
|
|
||||||
# What's new
|
|
||||||
# in 0.4
|
|
||||||
paper-$(PAPER)/whatsnew04.dvi: whatsnew04/whatsnew04.tex whatsnew04/conversion.tex
|
|
||||||
cd paper-$(PAPER) && $(MKDVI) ../whatsnew04/whatsnew04.tex
|
|
||||||
|
|
||||||
paper-$(PAPER)/whatsnew04.pdf: whatsnew04/whatsnew04.tex whatsnew04/conversion.tex
|
|
||||||
cd paper-$(PAPER) && $(MKPDF) ../whatsnew04/whatsnew04.tex
|
|
||||||
|
|
||||||
# The remaining part of the Makefile is concerned with various
|
|
||||||
# conversions, as described above. See also the README file.
|
|
||||||
|
|
||||||
info:
|
|
||||||
cd $(INFODIR) && $(MAKE) EMACS=$(EMACS)
|
|
||||||
|
|
||||||
# Targets to convert the manuals to HTML using Nikos Drakos' LaTeX to
|
|
||||||
# HTML converter. For more info on this program, see
|
|
||||||
# <URL:http://cbl.leeds.ac.uk/nikos/tex2html/doc/latex2html/latex2html.html>.
|
|
||||||
|
|
||||||
# Note that LaTeX2HTML inserts references to an icons directory in
|
|
||||||
# each page that it generates. I have placed a copy of this directory
|
|
||||||
# in the distribution to simplify the process of creating a
|
|
||||||
# self-contained HTML distribution; for this purpose I have also added
|
|
||||||
# a (trivial) index.html. Change the definition of $ICONSERVER in
|
|
||||||
# perl/l2hinit.perl to use a different location for the icons directory.
|
|
||||||
|
|
||||||
# If you have the standard LaTeX2HTML icons installed, the versions shipped
|
|
||||||
# with this documentation should be stored in a separate directory and used
|
|
||||||
# instead. The standard set does *not* include all the icons used in the
|
|
||||||
# Python documentation.
|
|
||||||
|
|
||||||
$(ALLCSSFILES): html/style.css
|
|
||||||
cp $< $@
|
|
||||||
|
|
||||||
$(INDEXFILES): $(COMMONPERL) html/about.dat tools/node2label.pl
|
|
||||||
|
|
||||||
html/acks.html: ACKS $(TOOLSDIR)/support.py $(TOOLSDIR)/mkackshtml
|
|
||||||
$(PYTHON) $(TOOLSDIR)/mkackshtml --address $(PYTHONDOCS) \
|
|
||||||
--favicon icons/pyfav.gif \
|
|
||||||
--output html/acks.html <ACKS
|
|
||||||
|
|
||||||
|
|
||||||
# html/index.html is dependent on $(INDEXFILES) since we want the date
|
|
||||||
# on the front index to be updated whenever any of the child documents
|
|
||||||
# are updated and boilerplate.tex uses \today as the date. The index
|
|
||||||
# files are not used to actually generate content.
|
|
||||||
|
|
||||||
BOILERPLATE=texinputs/boilerplate.tex
|
|
||||||
html/index.html: $(INDEXFILES)
|
|
||||||
html/index.html: html/index.html.in $(BOILERPLATE) tools/rewrite.py
|
|
||||||
$(PYTHON) tools/rewrite.py $(BOILERPLATE) \
|
|
||||||
RELEASE=$(RELEASE) WHATSNEW=$(WHATSNEW) \
|
|
||||||
<$< >$@
|
|
||||||
|
|
||||||
html/modindex.html:
|
|
||||||
touch html/modindex.html
|
|
||||||
|
|
||||||
html: $(ALLHTMLFILES) $(HTMLCSSFILES)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
manual: html/manual/MyHDL.html html/manual/MyHDL.css
|
|
||||||
html/manual/MyHDL.html: $(MANUALFILES)
|
|
||||||
$(MKHTML) --dir html/manual manual/MyHDL.tex
|
|
||||||
|
|
||||||
whatsnew03: html/whatsnew03/whatsnew03.html
|
|
||||||
html/whatsnew03/whatsnew03.html: whatsnew03/whatsnew03.tex
|
|
||||||
$(MKHTML) --dir html/whatsnew03 whatsnew03/whatsnew03.tex
|
|
||||||
|
|
||||||
whatsnew04: html/whatsnew04/whatsnew04.html
|
|
||||||
html/whatsnew04/whatsnew04.html: whatsnew04/whatsnew04.tex whatsnew04/conversion.tex
|
|
||||||
$(MKHTML) --dir html/whatsnew04 whatsnew04/whatsnew04.tex
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# webchecker needs an extra flag to process the huge index from the libref
|
|
||||||
WEBCHECKER=$(PYTHON) ../Tools/webchecker/webchecker.py
|
|
||||||
HTMLBASE= file:`pwd`/html
|
|
||||||
|
|
||||||
webcheck: $(ALLHTMLFILES)
|
|
||||||
$(WEBCHECKER) $(HTMLBASE)/manual/
|
|
||||||
$(WEBCHECKER) $(HTMLBASE)/doc/
|
|
||||||
|
|
||||||
fastwebcheck: $(ALLHTMLFILES)
|
|
||||||
$(WEBCHECKER) -x $(HTMLBASE)/manual/
|
|
||||||
$(WEBCHECKER) -x $(HTMLBASE)/doc/
|
|
||||||
|
|
||||||
|
|
||||||
# Release packaging targets:
|
|
||||||
|
|
||||||
paper-$(PAPER)/README: $(PSFILES) $(TOOLSDIR)/getpagecounts
|
|
||||||
cd paper-$(PAPER) && ../$(TOOLSDIR)/getpagecounts -r $(RELEASE) >../$@
|
|
||||||
|
|
||||||
info-$(RELEASE).tgz: info
|
|
||||||
cd $(INFODIR) && tar cf - README python.dir python-*.info* \
|
|
||||||
| gzip -9 >$@
|
|
||||||
|
|
||||||
info-$(RELEASE).tar.bz2: info
|
|
||||||
cd $(INFODIR) && tar cf - README python.dir python-*.info* \
|
|
||||||
| bzip2 -9 >$@
|
|
||||||
|
|
||||||
latex-$(RELEASE).tgz:
|
|
||||||
$(PYTHON) $(TOOLSDIR)/mksourcepkg --gzip $(RELEASE)
|
|
||||||
|
|
||||||
latex-$(RELEASE).tar.bz2:
|
|
||||||
$(PYTHON) $(TOOLSDIR)/mksourcepkg --bzip2 $(RELEASE)
|
|
||||||
|
|
||||||
latex-$(RELEASE).zip:
|
|
||||||
rm -f $@
|
|
||||||
$(PYTHON) $(TOOLSDIR)/mksourcepkg --zip $(RELEASE)
|
|
||||||
|
|
||||||
pdf-$(PAPER)-$(RELEASE).tar: $(PDFFILES)
|
|
||||||
rm -f $@
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/*.pdf Python-Docs-$(RELEASE)
|
|
||||||
tar cf $@ Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
pdf-$(PAPER)-$(RELEASE).tgz: pdf-$(PAPER)-$(RELEASE).tar
|
|
||||||
gzip -9 <$? >$@
|
|
||||||
|
|
||||||
pdf-$(PAPER)-$(RELEASE).tar.bz2: pdf-$(PAPER)-$(RELEASE).tar
|
|
||||||
bzip2 -9 <$? >$@
|
|
||||||
|
|
||||||
pdf-$(PAPER)-$(RELEASE).zip: pdf
|
|
||||||
rm -f $@
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/*.pdf Python-Docs-$(RELEASE)
|
|
||||||
zip -q -r -9 $@ Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
postscript-$(PAPER)-$(RELEASE).tar: $(PSFILES) paper-$(PAPER)/README
|
|
||||||
rm -f $@
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/*.ps Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/README Python-Docs-$(RELEASE)
|
|
||||||
tar cf $@ Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
postscript-$(PAPER)-$(RELEASE).tar.bz2: postscript-$(PAPER)-$(RELEASE).tar
|
|
||||||
bzip2 -9 <$< >$@
|
|
||||||
|
|
||||||
postscript-$(PAPER)-$(RELEASE).tgz: postscript-$(PAPER)-$(RELEASE).tar
|
|
||||||
gzip -9 <$< >$@
|
|
||||||
|
|
||||||
postscript-$(PAPER)-$(RELEASE).zip: $(PSFILES) paper-$(PAPER)/README
|
|
||||||
rm -f $@
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/*.ps Python-Docs-$(RELEASE)
|
|
||||||
cp paper-$(PAPER)/README Python-Docs-$(RELEASE)
|
|
||||||
zip -q -r -9 $@ Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
HTMLPKGFILES=*.html */*.css */*.html */*.gif */*.txt
|
|
||||||
|
|
||||||
html-$(RELEASE).tar: $(ALLHTMLFILES) $(HTMLCSSFILES)
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cd html && tar cf ../temp.tar $(HTMLPKGFILES)
|
|
||||||
cd Python-Docs-$(RELEASE) && tar xf ../temp.tar
|
|
||||||
rm temp.tar
|
|
||||||
tar cf html-$(RELEASE).tar Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
html-$(RELEASE).tgz: html-$(RELEASE).tar
|
|
||||||
gzip -9 <$? >$@
|
|
||||||
|
|
||||||
html-$(RELEASE).tar.bz2: html-$(RELEASE).tar
|
|
||||||
bzip2 -9 <$? >$@
|
|
||||||
|
|
||||||
html-$(RELEASE).zip: $(ALLHTMLFILES) $(HTMLCSSFILES)
|
|
||||||
rm -f $@
|
|
||||||
mkdir Python-Docs-$(RELEASE)
|
|
||||||
cd html && tar cf ../temp.tar $(HTMLPKGFILES)
|
|
||||||
cd Python-Docs-$(RELEASE) && tar xf ../temp.tar
|
|
||||||
rm temp.tar
|
|
||||||
zip -q -r -9 $@ Python-Docs-$(RELEASE)
|
|
||||||
rm -r Python-Docs-$(RELEASE)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# convenience targets:
|
|
||||||
|
|
||||||
tarhtml: html-$(RELEASE).tgz
|
|
||||||
tarinfo: info-$(RELEASE).tgz
|
|
||||||
tarps: postscript-$(PAPER)-$(RELEASE).tgz
|
|
||||||
tarpdf: pdf-$(PAPER)-$(RELEASE).tgz
|
|
||||||
tarlatex: latex-$(RELEASE).tgz
|
|
||||||
|
|
||||||
tarballs: tarpdf tarps tarhtml
|
|
||||||
|
|
||||||
ziphtml: html-$(RELEASE).zip
|
|
||||||
zipps: postscript-$(PAPER)-$(RELEASE).zip
|
|
||||||
zippdf: pdf-$(PAPER)-$(RELEASE).zip
|
|
||||||
ziplatex: latex-$(RELEASE).zip
|
|
||||||
|
|
||||||
zips: zippdf zipps ziphtml
|
|
||||||
|
|
||||||
bziphtml: html-$(RELEASE).tar.bz2
|
|
||||||
bzipinfo: info-$(RELEASE).tar.bz2
|
|
||||||
bzipps: postscript-$(PAPER)-$(RELEASE).tar.bz2
|
|
||||||
bzippdf: pdf-$(PAPER)-$(RELEASE).tar.bz2
|
|
||||||
bziplatex: latex-$(RELEASE).tar.bz2
|
|
||||||
|
|
||||||
bzips: bzippdf bzipps bziphtml
|
|
||||||
|
|
||||||
disthtml: tarhtml bziphtml ziphtml
|
|
||||||
distinfo: tarinfo bzipinfo
|
|
||||||
distps: tarps bzipps zipps
|
|
||||||
distpdf: tarpdf bzippdf zippdf
|
|
||||||
distlatex: tarlatex bziplatex ziplatex
|
|
||||||
|
|
||||||
paperdist: distpdf distps
|
|
||||||
edist: disthtml
|
|
||||||
|
|
||||||
distfiles: paperdist edist
|
|
||||||
$(TOOLSDIR)/mksourcepkg --all $(RELEASE)
|
|
||||||
$(TOOLSDIR)/mkpkglist >pkglist.html
|
|
||||||
|
|
||||||
|
|
||||||
# Housekeeping targets
|
|
||||||
|
|
||||||
# Remove temporary files; all except the following:
|
|
||||||
# - sources: .tex, .bib, .sty, *.cls
|
|
||||||
# - useful results: .dvi, .pdf, .ps, .texi, .info
|
|
||||||
clean:
|
|
||||||
rm -f html-$(RELEASE).tar
|
|
||||||
cd $(INFODIR) && $(MAKE) clean
|
|
||||||
|
|
||||||
# Remove temporaries as well as final products
|
|
||||||
clobber:
|
|
||||||
rm -f html-$(RELEASE).tar
|
|
||||||
rm -f html-$(RELEASE).tgz info-$(RELEASE).tgz
|
|
||||||
rm -f pdf-$(RELEASE).tgz postscript-$(RELEASE).tgz
|
|
||||||
rm -f latex-$(RELEASE).tgz html-$(RELEASE).zip
|
|
||||||
rm -f pdf-$(RELEASE).zip postscript-$(RELEASE).zip
|
|
||||||
rm -f $(DVIFILES) $(PSFILES) $(PDFFILES)
|
|
||||||
cd $(INFODIR) && $(MAKE) clobber
|
|
||||||
rm -f paper-$(PAPER)/*.tex paper-$(PAPER)/*.ind paper-$(PAPER)/*.idx
|
|
||||||
rm -f paper-$(PAPER)/*.l2h paper-$(PAPER)/*.how paper-$(PAPER)/README
|
|
||||||
rm -rf html/index.html html/modindex.html html/acks.html
|
|
||||||
rm -rf html/manual/
|
|
||||||
rm -rf html/whatsnew03/
|
|
||||||
rm -rf html/whatsnew04/
|
|
||||||
|
|
||||||
realclean distclean: clobber
|
|
@ -1,34 +0,0 @@
|
|||||||
# LaTeX source dependencies.
|
|
||||||
|
|
||||||
COMMONSTYLES= texinputs/python.sty \
|
|
||||||
texinputs/pypaper.sty
|
|
||||||
|
|
||||||
INDEXSTYLES=texinputs/python.ist
|
|
||||||
|
|
||||||
COMMONTEX= texinputs/copyright.tex \
|
|
||||||
texinputs/license.tex \
|
|
||||||
texinputs/boilerplate.tex
|
|
||||||
|
|
||||||
MANSTYLES= texinputs/fncychap.sty \
|
|
||||||
texinputs/manual.cls \
|
|
||||||
$(COMMONSTYLES)
|
|
||||||
|
|
||||||
HOWTOSTYLES= texinputs/howto.cls \
|
|
||||||
$(COMMONSTYLES)
|
|
||||||
|
|
||||||
|
|
||||||
DOCFILES= $(HOWTOSTYLES) \
|
|
||||||
texinputs/boilerplate.tex \
|
|
||||||
texinputs/ltxmarkup.sty \
|
|
||||||
doc/doc.tex
|
|
||||||
|
|
||||||
# LaTeX source files for the MyHDL Manual
|
|
||||||
MANUALFILES= $(MANSTYLES) $(INDEXSTYLES) $(COMMONTEX) \
|
|
||||||
manual/MyHDL.tex \
|
|
||||||
manual/background.tex \
|
|
||||||
manual/intro.tex \
|
|
||||||
manual/modeling.tex \
|
|
||||||
manual/unittest.tex \
|
|
||||||
manual/cosimulation.tex \
|
|
||||||
manual/conversion.tex \
|
|
||||||
manual/reference.tex
|
|
231
olddoc/README
@ -1,231 +0,0 @@
|
|||||||
Python standard documentation -- in LaTeX
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
This directory contains the LaTeX sources to the Python documentation
|
|
||||||
and tools required to support the formatting process. The documents
|
|
||||||
now require LaTeX2e; LaTeX 2.09 compatibility has been dropped.
|
|
||||||
|
|
||||||
If you don't have LaTeX, or if you'd rather not format the
|
|
||||||
documentation yourself, you can ftp a tar file containing HTML, PDF,
|
|
||||||
or PostScript versions of all documents. Additional formats may be
|
|
||||||
available. These should be in the same place where you fetched the
|
|
||||||
main Python distribution (try <http://www.python.org/> or
|
|
||||||
<ftp://ftp.python.org/pub/python/>).
|
|
||||||
|
|
||||||
The following are the LaTeX source files:
|
|
||||||
|
|
||||||
api/*.tex Python/C API Reference Manual
|
|
||||||
doc/*.tex Documenting Python
|
|
||||||
ext/*.tex Extending and Embedding the Python Interpreter
|
|
||||||
lib/*.tex Python Library Reference
|
|
||||||
mac/*.tex Macintosh Library Modules
|
|
||||||
ref/*.tex Python Reference Manual
|
|
||||||
tut/*.tex Python Tutorial
|
|
||||||
inst/*.tex Installing Python Modules
|
|
||||||
dist/*.tex Distributing Python Modules
|
|
||||||
|
|
||||||
Most use the "manual" document class and "python" package, derived from
|
|
||||||
the old "myformat.sty" style file. The Macintosh Library Modules
|
|
||||||
document uses the "howto" document class instead. These contains many
|
|
||||||
macro definitions useful in documenting Python, and set some style
|
|
||||||
parameters.
|
|
||||||
|
|
||||||
There's a Makefile to call LaTeX and the other utilities in the right
|
|
||||||
order and the right number of times. By default, it will build the
|
|
||||||
HTML version of the documnetation, but DVI, PDF, and PostScript can
|
|
||||||
also be made. To view the generated HTML, point your favorite browser
|
|
||||||
at the top-level index (html/index.html) after running "make".
|
|
||||||
|
|
||||||
The Makefile can also produce DVI files for each document made; to
|
|
||||||
preview them, use xdvi. PostScript is produced by the same Makefile
|
|
||||||
target that produces the DVI files. This uses the dvips tool.
|
|
||||||
Printing depends on local conventions; at our site, we use lpr. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
make paper-letter/lib.ps # create lib.dvi and lib.ps
|
|
||||||
xdvi paper-letter/lib.dvi # preview lib.dvi
|
|
||||||
lpr paper-letter/lib.ps # print on default printer
|
|
||||||
|
|
||||||
|
|
||||||
What if I find a bug?
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
First, check that the bug is present in the development version of the
|
|
||||||
documentation at <http://python.sourceforge.net/devel-docs/>; we may
|
|
||||||
have already fixed it.
|
|
||||||
|
|
||||||
If we haven't, tell us about it. We'd like the documentation to be
|
|
||||||
complete and accurate, but have limited time. If you discover any
|
|
||||||
inconsistencies between the documentation and implementation, or just
|
|
||||||
have suggestions as to how to improve the documentation, let is know!
|
|
||||||
Specific bugs and patches should be reported using our bug & patch
|
|
||||||
databases at:
|
|
||||||
|
|
||||||
http://sourceforge.net/projects/python
|
|
||||||
|
|
||||||
Other suggestions or questions should be sent to the Python
|
|
||||||
Documentation Team:
|
|
||||||
|
|
||||||
python-docs@python.org
|
|
||||||
|
|
||||||
Thanks!
|
|
||||||
|
|
||||||
|
|
||||||
What happened to the Macintosh chapter of the Python Library Reference?
|
|
||||||
-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
The directory mac/ contains the LaTeX sources for the "Macintosh
|
|
||||||
Library Modules" manual; this is built using the standard build
|
|
||||||
targets, so check the proper output directory for your chosen format
|
|
||||||
and paper size.
|
|
||||||
|
|
||||||
|
|
||||||
What tools do I need?
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
You need to install Python; some of the scripts used to produce the
|
|
||||||
documentation are written in Python. You don't need this
|
|
||||||
documentation to install Python; instructions are included in the
|
|
||||||
README file in the Python distribution.
|
|
||||||
|
|
||||||
The simplest way to get the rest of the tools in the configuration we
|
|
||||||
used is to install the teTeX TeX distribution, versions 0.9 or newer.
|
|
||||||
More information is available on teTeX at <http://www.tug.org/tetex/>.
|
|
||||||
This is a Unix-only TeX distribution at this time. This documentation
|
|
||||||
release was tested with the 1.0.7 release, but there have been no
|
|
||||||
substantial changes since late in the 0.9 series, which we used
|
|
||||||
extensively for previous versions without any difficulty.
|
|
||||||
|
|
||||||
If you don't want to get teTeX, here is what you'll need:
|
|
||||||
|
|
||||||
To create DVI, PDF, or PostScript files:
|
|
||||||
|
|
||||||
- LaTeX2e, 1995/12/01 or newer. Older versions are likely to
|
|
||||||
choke.
|
|
||||||
|
|
||||||
- makeindex. This is used to produce the indexes for the
|
|
||||||
library reference and Python/C API reference.
|
|
||||||
|
|
||||||
To create PDF files:
|
|
||||||
|
|
||||||
- pdflatex. We used the one in the teTeX distribution (pdfTeX
|
|
||||||
version 3.14159-13d (Web2C 7.3.1) at the time of this
|
|
||||||
writing). Versions even a couple of patchlevels earlier are
|
|
||||||
highly likely to fail due to syntax changes for some of the
|
|
||||||
pdftex primitives.
|
|
||||||
|
|
||||||
To create PostScript files:
|
|
||||||
|
|
||||||
- dvips. Most TeX installations include this. If you don't
|
|
||||||
have one, check CTAN (<ftp://ctan.tug.org/tex-archive/>).
|
|
||||||
|
|
||||||
To create info files:
|
|
||||||
|
|
||||||
Note that info support is currently being revised using new
|
|
||||||
conversion tools by Michael Ernst <mernst@cs.washington.edu>.
|
|
||||||
|
|
||||||
- makeinfo. This is available from any GNU mirror.
|
|
||||||
|
|
||||||
- emacs or xemacs. Emacs is available from the same place as
|
|
||||||
makeinfo, and xemacs is available from ftp.xemacs.org.
|
|
||||||
|
|
||||||
- Perl. Find the software at
|
|
||||||
<http://language.perl.com/info/software.html>.
|
|
||||||
|
|
||||||
- HTML::Element. If you don't have this installed, you can get
|
|
||||||
this from CPAN. Use the command:
|
|
||||||
|
|
||||||
perl -e 'use CPAN; CPAN::install("HTML::Element");'
|
|
||||||
|
|
||||||
You may need to be root to do this.
|
|
||||||
|
|
||||||
To create HTML files:
|
|
||||||
|
|
||||||
- Perl 5.004_04 or newer. Find the software at
|
|
||||||
<http://language.perl.com/info/software.html>.
|
|
||||||
|
|
||||||
- LaTeX2HTML 99.2b8 or newer. Older versions are not
|
|
||||||
supported; each version changes enough that supporting
|
|
||||||
multiple versions is not likely to work. Many older
|
|
||||||
versions don't work with Perl 5.6 as well. This also screws
|
|
||||||
up code fragments. ;-( Releases are available at:
|
|
||||||
<http://www.latex2html.org/>.
|
|
||||||
|
|
||||||
|
|
||||||
What if Times fonts are not available?
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
As distributed, the LaTeX documents use PostScript Times fonts. This
|
|
||||||
is done since they are much better looking and produce smaller
|
|
||||||
PostScript files. If, however, your TeX installation does not support
|
|
||||||
them, they may be easily disabled. Edit the file
|
|
||||||
texinputs/pypaper.sty and comment out the line that starts
|
|
||||||
"\RequirePackage{times}" by inserting a "%" character at the beginning
|
|
||||||
of the line. If you're formatting the docs for A4 paper instead of
|
|
||||||
US-Letter paper, change paper-a4/pypaper.sty instead. An alternative
|
|
||||||
is to install the right fonts and LaTeX style file.
|
|
||||||
|
|
||||||
|
|
||||||
What if I want to use A4 paper?
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Instead of building the PostScript by giving the command "make ps",
|
|
||||||
give the command "make PAPER=a4 ps"; the output will be produced in
|
|
||||||
the paper-a4/ subdirectory. (You can use "make PAPER=a4 pdf" if you'd
|
|
||||||
rather have PDF output.)
|
|
||||||
|
|
||||||
|
|
||||||
Making HTML files
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The LaTeX documents can be converted to HTML using Nikos Drakos'
|
|
||||||
LaTeX2HTML converter. See the Makefile; after some twiddling, "make"
|
|
||||||
should do the trick.
|
|
||||||
|
|
||||||
|
|
||||||
What else is in here?
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
There is a new LaTeX document class called "howto". This is used for
|
|
||||||
the new series of Python HOWTO documents which is being coordinated by
|
|
||||||
Andrew Kuchling <akuchlin@mems-exchange.org>. The file
|
|
||||||
templates/howto.tex is a commented example which may be used as a
|
|
||||||
template. A Python script to "do the right thing" to format a howto
|
|
||||||
document is included as tools/mkhowto. These documents can be
|
|
||||||
formatted as HTML, PDF, PostScript, or ASCII files. Use "mkhowto
|
|
||||||
--help" for information on using the formatting tool.
|
|
||||||
|
|
||||||
For authors of module documentation, there is a file
|
|
||||||
templates/module.tex which may be used as a template for a module
|
|
||||||
section. This may be used in conjunction with either the howto or
|
|
||||||
manual document class. Create the documentation for a new module by
|
|
||||||
copying the template to lib<mymodule>.tex and editing according to the
|
|
||||||
instructions in the comments.
|
|
||||||
|
|
||||||
Documentation on the authoring Python documentation, including
|
|
||||||
information about both style and markup, is available in the
|
|
||||||
"Documenting Python" manual.
|
|
||||||
|
|
||||||
|
|
||||||
Copyright notice
|
|
||||||
================
|
|
||||||
|
|
||||||
The Python source is copyrighted, but you can freely use and copy it
|
|
||||||
as long as you don't change or remove the copyright notice:
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Copyright (c) 2000-2002 Python Software Foundation.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Copyright (c) 2000 BeOpen.com.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Copyright (c) 1995-2000 Corporation for National Research Initiatives.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Copyright (c) 1991-1995 Stichting Mathematisch Centrum.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
See the file "texinputs/license.tex" for information on usage and
|
|
||||||
redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
||||||
----------------------------------------------------------------------
|
|
@ -1,8 +0,0 @@
|
|||||||
Printing problems with pdf
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Apparently there is a problem with Acrobat5 and the Python
|
|
||||||
documentation flow I am using. The symptom is that the some pages of
|
|
||||||
the MyHDL.pdf file don't print correctly. The workaround is to print
|
|
||||||
from Acrobat4, xpdf or ghostview. Alternatively, you can try the
|
|
||||||
postscript file MyHDL.ps.
|
|
@ -1,24 +0,0 @@
|
|||||||
<p> This document was generated using the <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> translator.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright ©
|
|
||||||
1993, 1994, 1995, 1996, 1997, <a
|
|
||||||
href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos
|
|
||||||
Drakos</a>, Computer Based Learning Unit, University of
|
|
||||||
Leeds, and Copyright © 1997, 1998, <a
|
|
||||||
href="http://www.maths.mq.edu.au/;SPMtilde;ross/">Ross
|
|
||||||
Moore</a>, Mathematics Department, Macquarie University,
|
|
||||||
Sydney.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> The application of <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python
|
|
||||||
documentation has been heavily tailored by Fred L. Drake,
|
|
||||||
Jr. Original navigation icons were contributed by Christopher
|
|
||||||
Petrilli.
|
|
||||||
</p>
|
|
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 438 B |
Before Width: | Height: | Size: 649 B |
Before Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 529 B |
Before Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 598 B |
Before Width: | Height: | Size: 253 B |
Before Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 252 B |
Before Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 125 B |
Before Width: | Height: | Size: 316 B |
Before Width: | Height: | Size: 577 B |
@ -1,38 +0,0 @@
|
|||||||
<p> This document was generated using the <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> translator.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright ©
|
|
||||||
1993, 1994, 1995, 1996, 1997, <a
|
|
||||||
href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos
|
|
||||||
Drakos</a>, Computer Based Learning Unit, University of
|
|
||||||
Leeds, and Copyright © 1997, 1998, <a
|
|
||||||
href="http://www.maths.mq.edu.au/;SPMtilde;ross/">Ross
|
|
||||||
Moore</a>, Mathematics Department, Macquarie University,
|
|
||||||
Sydney.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> The application of <a
|
|
||||||
href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/">
|
|
||||||
<strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python
|
|
||||||
documentation has been heavily tailored by Fred L. Drake,
|
|
||||||
Jr. Original navigation icons were contributed by Christopher
|
|
||||||
Petrilli.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p> Jan Decaluwe reused the Python documentation flow to generate
|
|
||||||
the MyHDL documentation as much as he could; his sincere thanks and
|
|
||||||
appreciation go out to all who contributed to this flow and
|
|
||||||
made this part of his life so much easier.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h2>Comments and Questions</h2>
|
|
||||||
|
|
||||||
<p> General comments, questions and bug reports regarding this document
|
|
||||||
may be sent to <a href="mailto:jan@jandecaluwe.com">Jan Decaluwe</a>.
|
|
||||||
</p>
|
|
@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
* The first part of this is the standard CSS generated by LaTeX2HTML,
|
|
||||||
* with the "empty" declarations removed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
|
|
||||||
.math { font-family: "Century Schoolbook", serif; }
|
|
||||||
.math i { font-family: "Century Schoolbook", serif;
|
|
||||||
font-weight: bold }
|
|
||||||
.boldmath { font-family: "Century Schoolbook", serif;
|
|
||||||
font-weight: bold }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implement both fixed-size and relative sizes.
|
|
||||||
*
|
|
||||||
* I think these can be safely removed, as it doesn't appear that
|
|
||||||
* LaTeX2HTML ever generates these, even though these are carried
|
|
||||||
* over from the LaTeX2HTML stylesheet.
|
|
||||||
*/
|
|
||||||
small.xtiny { font-size : xx-small; }
|
|
||||||
small.tiny { font-size : x-small; }
|
|
||||||
small.scriptsize { font-size : smaller; }
|
|
||||||
small.footnotesize { font-size : small; }
|
|
||||||
big.xlarge { font-size : large; }
|
|
||||||
big.xxlarge { font-size : x-large; }
|
|
||||||
big.huge { font-size : larger; }
|
|
||||||
big.xhuge { font-size : xx-large; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Document-specific styles come next;
|
|
||||||
* these are added for the Python documentation.
|
|
||||||
*
|
|
||||||
* Note that the size specifications for the H* elements are because
|
|
||||||
* Netscape on Solaris otherwise doesn't get it right; they all end up
|
|
||||||
* the normal text size.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body { color: #000000;
|
|
||||||
background-color: #ffffff; }
|
|
||||||
|
|
||||||
a:active { color: #ff0000; }
|
|
||||||
a:link:hover { background-color: #bbeeff; }
|
|
||||||
a:visited:hover { background-color: #bbeeff; }
|
|
||||||
a:visited { color: #551a8b; }
|
|
||||||
a:link { color: #0000bb; }
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif;
|
|
||||||
font-weight: bold; }
|
|
||||||
h1 { font-size: 180%; }
|
|
||||||
h2 { font-size: 150%; }
|
|
||||||
h3, h4 { font-size: 120%; }
|
|
||||||
|
|
||||||
/* LaTeX2HTML insists on inserting <br> elements into headers which
|
|
||||||
* are marked with \label. This little bit of CSS magic ensures that
|
|
||||||
* these elements don't cause spurious whitespace to be added.
|
|
||||||
*/
|
|
||||||
h1>br, h2>br, h3>br,
|
|
||||||
h4>br, h5>br, h6>br { display: none; }
|
|
||||||
|
|
||||||
code, tt { font-family: "lucida typewriter", lucidatypewriter,
|
|
||||||
monospace; }
|
|
||||||
var { font-family: times, serif;
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
|
|
||||||
.typelabel { font-family: lucida, sans-serif; }
|
|
||||||
|
|
||||||
.navigation td { background-color: #99ccff;
|
|
||||||
font-weight: bold;
|
|
||||||
font-family: avantgarde, sans-serif;
|
|
||||||
font-size: 110%; }
|
|
||||||
|
|
||||||
div.warning { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 1em;
|
|
||||||
margin-left: 2em;
|
|
||||||
margin-right: 2em; }
|
|
||||||
|
|
||||||
div.warning .label { font-family: sans-serif;
|
|
||||||
font-size: 110%;
|
|
||||||
margin-right: 0.5em; }
|
|
||||||
|
|
||||||
div.note { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 1em;
|
|
||||||
margin-left: 2em;
|
|
||||||
margin-right: 2em; }
|
|
||||||
|
|
||||||
div.note .label { margin-right: 0.5em;
|
|
||||||
font-family: sans-serif; }
|
|
||||||
|
|
||||||
.release-info { font-style: italic; }
|
|
||||||
|
|
||||||
.titlegraphic { vertical-align: top; }
|
|
||||||
|
|
||||||
.verbatim pre { color: #00008b;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 100%; }
|
|
||||||
.verbatim { margin-left: 2em; }
|
|
||||||
.verbatim .footer { padding: 0.05in;
|
|
||||||
font-size: 85%;
|
|
||||||
background-color: #99ccff;
|
|
||||||
margin-right: 0.5in; }
|
|
||||||
|
|
||||||
.grammar { background-color: #99ccff;
|
|
||||||
margin-right: 0.5in;
|
|
||||||
padding: 0.05in; }
|
|
||||||
.grammar-footer { padding: 0.05in;
|
|
||||||
font-size: 85%; }
|
|
||||||
|
|
||||||
.productions { background-color: #bbeeff; }
|
|
||||||
.productions a:active { color: #ff0000; }
|
|
||||||
.productions a:link:hover { background-color: #99ccff; }
|
|
||||||
.productions a:visited:hover { background-color: #99ccff; }
|
|
||||||
.productions a:visited { color: #551a8b; }
|
|
||||||
.productions a:link { color: #0000bb; }
|
|
||||||
.productions table { vertical-align: baseline; }
|
|
||||||
|
|
||||||
.email { font-family: avantgarde, sans-serif; }
|
|
||||||
.mailheader { font-family: avantgarde, sans-serif; }
|
|
||||||
.mimetype { font-family: avantgarde, sans-serif; }
|
|
||||||
.newsgroup { font-family: avantgarde, sans-serif; }
|
|
||||||
.url { font-family: avantgarde, sans-serif; }
|
|
||||||
.file { font-family: avantgarde, sans-serif; }
|
|
||||||
.menuselection { font-family: avantgarde, sans-serif; }
|
|
||||||
|
|
||||||
.tableheader { background-color: #99ccff;
|
|
||||||
font-family: avantgarde, sans-serif; }
|
|
||||||
|
|
||||||
.refcount-info { font-style: italic; }
|
|
||||||
.refcount-info .value { font-weight: bold;
|
|
||||||
color: #006600; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some decoration for the "See also:" blocks, in part inspired by some of
|
|
||||||
* the styling on Lars Marius Garshol's XSA pages.
|
|
||||||
* (The blue in the navigation bars is #99CCFF.)
|
|
||||||
*/
|
|
||||||
.seealso { background-color: #fffaf0;
|
|
||||||
border: thin solid black;
|
|
||||||
padding: 0pt 1em 4pt 1em; }
|
|
||||||
|
|
||||||
.seealso .heading { font-size: 110%; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class 'availability' is used for module availability statements at
|
|
||||||
* the top of modules.
|
|
||||||
*/
|
|
||||||
.availability .platform { font-weight: bold; }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some specialization for printed output.
|
|
||||||
*/
|
|
||||||
@media print {
|
|
||||||
.online-navigation { display: none; }
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
*.info*
|
|
||||||
*.texi
|
|
@ -1,70 +0,0 @@
|
|||||||
# Generate the Python "info" documentation.
|
|
||||||
|
|
||||||
TOPDIR=..
|
|
||||||
TOOLSDIR=$(TOPDIR)/tools
|
|
||||||
HTMLDIR=$(TOPDIR)/html
|
|
||||||
|
|
||||||
# The emacs binary used to build the info docs. GNU Emacs 21 is required.
|
|
||||||
EMACS=emacs
|
|
||||||
|
|
||||||
MKINFO=$(TOOLSDIR)/mkinfo
|
|
||||||
SCRIPTS=$(TOOLSDIR)/checkargs.pm $(TOOLSDIR)/mkinfo $(TOOLSDIR)/py2texi.el
|
|
||||||
|
|
||||||
# set VERSION to code the VERSION number into the info file name
|
|
||||||
# allowing installation of more than one set of python info docs
|
|
||||||
# into the same directory
|
|
||||||
VERSION=
|
|
||||||
|
|
||||||
all: check-emacs-version \
|
|
||||||
python$(VERSION)-api.info python$(VERSION)-ext.info \
|
|
||||||
python$(VERSION)-lib.info python$(VERSION)-ref.info \
|
|
||||||
python$(VERSION)-tut.info python$(VERSION)-dist.info
|
|
||||||
|
|
||||||
# python$(VERSION)-doc.info python$(VERSION)-inst.info
|
|
||||||
# python$(VERSION)-mac.info
|
|
||||||
|
|
||||||
check-emacs-version:
|
|
||||||
@v="`$(EMACS) --version 2>&1 | egrep '^(GNU |X)Emacs [12]*'`"; \
|
|
||||||
if `echo "$$v" | grep '^GNU Emacs 21' >/dev/null 2>&1`; then \
|
|
||||||
echo "Using $(EMACS) to build the info docs"; \
|
|
||||||
else \
|
|
||||||
echo "GNU Emacs 21 is required to build the info docs"; \
|
|
||||||
echo "Found $$v"; \
|
|
||||||
false; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
python$(VERSION)-api.info: ../api/api.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
python$(VERSION)-ext.info: ../ext/ext.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
python$(VERSION)-lib.info: ../lib/lib.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
# Not built by default; the conversion doesn't really handle it well.
|
|
||||||
python$(VERSION)-mac.info: ../mac/mac.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
python$(VERSION)-ref.info: ../ref/ref.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
python$(VERSION)-tut.info: ../tut/tut.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
# Not built by default; the conversion doesn't handle it at all.
|
|
||||||
python$(VERSION)-doc.info: ../doc/doc.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
python$(VERSION)-dist.info: ../dist/dist.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
# Not built by default; the conversion chokes on two @end multitable's
|
|
||||||
python$(VERSION)-inst.info: ../inst/inst.tex $(SCRIPTS)
|
|
||||||
EMACS=$(EMACS) $(MKINFO) $< $*.texi $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f *.texi~ *.texi
|
|
||||||
|
|
||||||
clobber: clean
|
|
||||||
rm -f *.texi python*-*.info python*-*.info-[0-9]*
|
|
@ -1,21 +0,0 @@
|
|||||||
This archive contains the standard Python documentation in GNU info
|
|
||||||
format. Five manuals are included:
|
|
||||||
|
|
||||||
python-ref.info* Python Reference Manual
|
|
||||||
python-mac.info* Python Macintosh Modules
|
|
||||||
python-lib.info* Python Library Reference
|
|
||||||
python-ext.info* Extending and Embedding the Python Interpreter
|
|
||||||
python-api.info* Python/C API Reference
|
|
||||||
python-tut.info* Python Tutorial
|
|
||||||
|
|
||||||
The file python.dir is a fragment of a "dir" file that can be used to
|
|
||||||
incorporate these documents into an existing GNU info installation:
|
|
||||||
insert the contents of this file into the "dir" or "localdir" file at
|
|
||||||
an appropriate point and copy the python-*.info* files to the same
|
|
||||||
directory.
|
|
||||||
|
|
||||||
Thanks go to Milan Zamazal <pdm@zamazal.org> for providing this
|
|
||||||
conversion to the info format.
|
|
||||||
|
|
||||||
Questions and comments on these documents should be directed to
|
|
||||||
python-docs@python.org.
|
|
@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
Python Standard Documentation
|
|
||||||
|
|
||||||
* Python Library: (python-lib). Python Library Reference
|
|
||||||
* Python Mac Modules: (python-mac). Python Macintosh Modules
|
|
||||||
* Python Reference: (python-ref). Python Reference Manual
|
|
||||||
* Python API: (python-api). Python/C API Reference Manual
|
|
||||||
* Python Extending: (python-ext). Extending & Embedding Python
|
|
||||||
* Python Tutorial: (python-tut). Python Tutorial
|
|
||||||
* Documenting Python: (python-doc). Documenting Python
|
|
||||||
* Installing Modules: (python-inst). Installing Python Modules
|
|
||||||
* Distributing Modules: (python-dist). Distributing Python Modules
|
|
@ -1,101 +0,0 @@
|
|||||||
\documentclass{manual}
|
|
||||||
\usepackage{palatino}
|
|
||||||
\renewcommand{\ttdefault}{cmtt}
|
|
||||||
\renewcommand{\sfdefault}{cmss}
|
|
||||||
\newcommand{\myhdl}{\protect \mbox{MyHDL}}
|
|
||||||
\usepackage{graphicx}
|
|
||||||
|
|
||||||
\title{The \myhdl\ manual}
|
|
||||||
|
|
||||||
\input{boilerplate}
|
|
||||||
|
|
||||||
\makeindex
|
|
||||||
|
|
||||||
\begin{document}
|
|
||||||
|
|
||||||
\maketitle
|
|
||||||
|
|
||||||
\input{copyright}
|
|
||||||
|
|
||||||
\begin{abstract}
|
|
||||||
|
|
||||||
\noindent
|
|
||||||
|
|
||||||
The goal of the \myhdl{} project is to empower hardware designers with
|
|
||||||
the elegance and simplicity of the Python language.
|
|
||||||
|
|
||||||
\myhdl{} is a free, open-source (LGPL) package for using Python as a
|
|
||||||
hardware description and verification language. Python is a very high
|
|
||||||
level language, and hardware designers can use its full power to model
|
|
||||||
and simulate their designs. Moreover, \myhdl{} can convert a design to
|
|
||||||
Verilog. In combination with an external synthesis tool, it provides a
|
|
||||||
complete path from Python to a silicon implementation.
|
|
||||||
|
|
||||||
\emph{Modeling}
|
|
||||||
|
|
||||||
|
|
||||||
Python's power and clarity make \myhdl{} an ideal solution for high level
|
|
||||||
modeling. Python is famous for enabling elegant solutions to complex
|
|
||||||
modeling problems. Moreover, Python is outstanding for rapid
|
|
||||||
application development and experimentation.
|
|
||||||
|
|
||||||
The key idea behind \myhdl{} is the use of Python generators to model
|
|
||||||
hardware concurrency. Generators are best described as resumable
|
|
||||||
functions. In \myhdl{}, generators are used in a specific way so that
|
|
||||||
they become similar to always blocks in Verilog or processes in VHDL.
|
|
||||||
|
|
||||||
A hardware module is modeled as a function that returns any number of
|
|
||||||
generators. This approach makes it straightforward to support features
|
|
||||||
such as arbitrary hierarchy, named port association, arrays of
|
|
||||||
instances, and conditional instantiation.
|
|
||||||
|
|
||||||
Furthermore, \myhdl{} provides classes that implement traditional
|
|
||||||
hardware description concepts. It provides a signal class to support
|
|
||||||
communication between generators, a class to support bit oriented
|
|
||||||
operations, and a class for enumeration types.
|
|
||||||
|
|
||||||
\emph{Simulation and Verification}
|
|
||||||
|
|
||||||
The built-in simulator runs on top of the Python interpreter. It
|
|
||||||
supports waveform viewing by tracing signal changes in a VCD file.
|
|
||||||
|
|
||||||
With \myhdl{}, the Python unit test framework can be used on hardware
|
|
||||||
designs. Although unit testing is a popular modern software
|
|
||||||
verification technique, it is not yet common in the hardware design
|
|
||||||
world, making it one more area in which \myhdl{} innovates.
|
|
||||||
|
|
||||||
\myhdl{} can also be used as hardware verification language for VHDL and
|
|
||||||
Verilog designs, by co-simulation with traditional HDL simulators.
|
|
||||||
|
|
||||||
\emph{Conversion to Verilog}
|
|
||||||
|
|
||||||
The converter to Verilog works on an instantiated design that has been
|
|
||||||
fully elaborated. Consequently, the original design structure can be
|
|
||||||
arbitrarily complex.
|
|
||||||
|
|
||||||
The converter automates certain tasks that are tedious or hard in
|
|
||||||
Verilog directly. Notable features are the possibility to choose
|
|
||||||
between various FSM state encodings based on a single attribute, the
|
|
||||||
mapping of certain high-level objects to RAM and ROM descriptions, and
|
|
||||||
the automated handling of signed arithmetic issues.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\end{abstract}
|
|
||||||
|
|
||||||
\tableofcontents
|
|
||||||
|
|
||||||
\input{background.tex}
|
|
||||||
\input{intro.tex}
|
|
||||||
\input{modeling.tex}
|
|
||||||
\input{unittest.tex}
|
|
||||||
\input{cosimulation.tex}
|
|
||||||
|
|
||||||
\chapter{Conversion to Verilog\label{conv}}
|
|
||||||
\input{conversion.tex}
|
|
||||||
|
|
||||||
\input{reference.tex}
|
|
||||||
|
|
||||||
\input{MyHDL.ind}
|
|
||||||
|
|
||||||
\end{document}
|
|
@ -1,167 +0,0 @@
|
|||||||
\chapter{Background information \label{background}}
|
|
||||||
|
|
||||||
\section{Prerequisites \label{prerequisites}}
|
|
||||||
|
|
||||||
You need a basic understanding of Python to use \myhdl{}.
|
|
||||||
If you don't know Python, don't worry: it
|
|
||||||
it is one of the easiest programming languages to
|
|
||||||
learn~\footnote{You must be bored by such claims, but in Python's
|
|
||||||
case it's true.}. Learning Python is one of the best time
|
|
||||||
investments that engineering professionals can make~\footnote{I am not
|
|
||||||
biased.}.
|
|
||||||
|
|
||||||
For starters, \url{http://www.python.org/doc/current/tut/tut.html} is
|
|
||||||
probably the best choice for an on-line tutorial. For alternatives,
|
|
||||||
see \url{http://www.python.org/doc/Newbies.html}.
|
|
||||||
|
|
||||||
A working knowledge of a hardware description language such as Verilog
|
|
||||||
or VHDL is helpful.
|
|
||||||
|
|
||||||
Code examples in this manual are sometimes shortened for clarity.
|
|
||||||
Complete executable examples can be found in the distribution directory at
|
|
||||||
\file{example/manual/}.
|
|
||||||
|
|
||||||
\section{A small tutorial on generators \label{tutorial}}
|
|
||||||
\index{generators!tutorial on}
|
|
||||||
|
|
||||||
Generators are a relatively recent Python feature. They
|
|
||||||
were introduced in Python~2.2.
|
|
||||||
Because generators are the key concept in
|
|
||||||
\myhdl{}, a small tutorial is included a here.
|
|
||||||
|
|
||||||
Consider the following nonsensical function:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def function():
|
|
||||||
for i in range(5):
|
|
||||||
return i
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
You can see why it doesn't make a lot of sense. As soon as the first
|
|
||||||
loop iteration is entered, the function returns:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
>>> function()
|
|
||||||
0
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Returning is fatal for the function call. Further loop iterations
|
|
||||||
never get a chance, and nothing is left over from the function call
|
|
||||||
when it returns.
|
|
||||||
|
|
||||||
To change the function into a generator function, we replace
|
|
||||||
\keyword{return} with \keyword{yield}:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def generator():
|
|
||||||
for i in range(5):
|
|
||||||
yield i
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Now we get:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
>>> generator()
|
|
||||||
<generator object at 0x815d5a8>
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
When a generator function is called, it returns a generator object. A
|
|
||||||
generator object supports the iterator protocol, which is an expensive
|
|
||||||
way of saying that you can let it generate subsequent values by
|
|
||||||
calling its \function{next()} method:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
>>> g = generator()
|
|
||||||
>>> g.next()
|
|
||||||
0
|
|
||||||
>>> g.next()
|
|
||||||
1
|
|
||||||
>>> g.next()
|
|
||||||
2
|
|
||||||
>>> g.next()
|
|
||||||
3
|
|
||||||
>>> g.next()
|
|
||||||
4
|
|
||||||
>>> g.next()
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
StopIteration
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Now we can generate the subsequent values from the for loop on demand,
|
|
||||||
until they are exhausted. What happens is that the
|
|
||||||
\keyword{yield} statement is like a
|
|
||||||
\keyword{return}, except that it is non-fatal: the generator remembers
|
|
||||||
its state and the point in the code when it yielded. A higher order
|
|
||||||
agent can decide when to get the next value by calling the
|
|
||||||
generator's \function{next()} method. We say that generators are
|
|
||||||
\dfn{resumable functions}.
|
|
||||||
|
|
||||||
If you are familiar with hardware description languages, this may ring
|
|
||||||
a bell. In hardware simulations, there is also a higher order agent,
|
|
||||||
the Simulator, that interacts with such resumable functions; they are
|
|
||||||
called
|
|
||||||
\index{VHDL!process}%
|
|
||||||
\dfn{processes} in VHDL and
|
|
||||||
\index{Verilog!always block}%
|
|
||||||
\dfn{always blocks} in
|
|
||||||
Verilog. Similarly, Python generators provide an elegant
|
|
||||||
and efficient method to model concurrency, without having to resort to
|
|
||||||
some form of threading.
|
|
||||||
|
|
||||||
The use of generators to model concurrency is the first key concept in
|
|
||||||
\myhdl{}. The second key concept is a related one: in \myhdl{}, the
|
|
||||||
yielded values are used to specify the conditions on which the
|
|
||||||
generator should wait before resuming. In other words, \keyword{yield}
|
|
||||||
statements work as general
|
|
||||||
\index{sensitivity list}%
|
|
||||||
sensitivity lists.
|
|
||||||
|
|
||||||
For more info about generators, consult the on-line Python
|
|
||||||
documentation, e.g. at \url{http://www.python.org/doc/2.2.2/whatsnew}.
|
|
||||||
|
|
||||||
|
|
||||||
\section{About decorators \label{deco}}
|
|
||||||
\index{decorators!about}
|
|
||||||
|
|
||||||
Python 2.4 introduced a new feature called decorators. MyHDL 0.5 takes
|
|
||||||
advantage of this new feature by defining a number of decorators that
|
|
||||||
facilitate hardware descriptions. However, many users may not yet be familiar with
|
|
||||||
decorators. Therefore, an introduction is included here.
|
|
||||||
|
|
||||||
A decorator consists of special syntax in front of a function
|
|
||||||
declaration. It refers to a decorator function. The decorator function
|
|
||||||
automatically transforms the declared function into some other
|
|
||||||
callable object.
|
|
||||||
|
|
||||||
A decorator function \function{deco} is used in a decorator statement as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
@deco
|
|
||||||
def func(arg1, arg2, ...):
|
|
||||||
<body>
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This code is equivalent to the following:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def func(arg1, arg2, ...):
|
|
||||||
<body>
|
|
||||||
func = deco(func)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Note that the decorator statement goes directly in front of the
|
|
||||||
function declaration, and that the function name \function{func} is automatically
|
|
||||||
reused for the final result.
|
|
||||||
|
|
||||||
MyHDL 0.5 uses decorators to create ready-to-simulate generators
|
|
||||||
from local function definitions. Their functionality
|
|
||||||
and usage will be described extensively in this manual.
|
|
||||||
|
|
||||||
For more info about Python decorators, consult the on-line Python
|
|
||||||
documentation, e.g. at \url{http://www.python.org/doc/2.4/whatsnew/node6.html}.
|
|
||||||
|
|
||||||
\begin{notice}[warning]
|
|
||||||
Because MyHDL 0.5 uses decorators, it requires Python 2.4 or a
|
|
||||||
later version.
|
|
||||||
\end{notice}
|
|
@ -1,416 +0,0 @@
|
|||||||
\chapter{Co-simulation with Verilog and VHDL \label{cosim}}
|
|
||||||
|
|
||||||
\section{Introduction \label{cosim-intro}}
|
|
||||||
|
|
||||||
One of the most exciting possibilities of \myhdl\
|
|
||||||
is to use it as a hardware verification language (HVL).
|
|
||||||
A HVL is a language used to write test benches and
|
|
||||||
verification environments, and to control simulations.
|
|
||||||
|
|
||||||
Nowadays, it is generally acknowledged that HVLs should be equipped
|
|
||||||
with modern software techniques, such as object orientation. The
|
|
||||||
reason is that verification it the most complex and time-consuming
|
|
||||||
task of the design process. Consequently, every useful technique is
|
|
||||||
welcome. Moreover, test benches are not required to be
|
|
||||||
implementable. Therefore, unlike with synthesizable code, there
|
|
||||||
are no constraints on creativity.
|
|
||||||
|
|
||||||
Technically, verification of a design implemented in
|
|
||||||
another language requires co-simulation. \myhdl\ is
|
|
||||||
enabled for co-simulation with any HDL simulator that
|
|
||||||
has a procedural language interface (PLI). The \myhdl\
|
|
||||||
side is designed to be independent of a particular
|
|
||||||
simulator, On the other hand, for each HDL simulator a specific
|
|
||||||
PLI module will have to be written in C. Currently,
|
|
||||||
the \myhdl\ release contains a PLI module for
|
|
||||||
two Verilog simulators: Icarus and Cver.
|
|
||||||
|
|
||||||
\section{The HDL side \label{cosim-hdl}}
|
|
||||||
|
|
||||||
To introduce co-simulation, we will continue to use the Gray encoder
|
|
||||||
example from the previous chapters. Suppose that we want to
|
|
||||||
synthesize it and write it in Verilog for that purpose. Clearly we would
|
|
||||||
like to reuse our unit test verification environment.
|
|
||||||
|
|
||||||
To start, let's recall how the Gray encoder in \myhdl{} looks like:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def bin2gray(B, G, width):
|
|
||||||
""" Gray encoder.
|
|
||||||
|
|
||||||
B -- input intbv signal, binary encoded
|
|
||||||
G -- output intbv signal, gray encoded
|
|
||||||
width -- bit width
|
|
||||||
"""
|
|
||||||
|
|
||||||
@always_comb
|
|
||||||
def logic():
|
|
||||||
for i in range(width):
|
|
||||||
G.next[i] = B[i+1] ^ B[i]
|
|
||||||
|
|
||||||
return logic
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
To show the co-simulation flow, we don't need the Verilog
|
|
||||||
implementation yet, but only the interface. Our Gray encoder in
|
|
||||||
Verilog would have the following interface:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
module bin2gray(B, G);
|
|
||||||
|
|
||||||
parameter width = 8;
|
|
||||||
input [width-1:0] B;
|
|
||||||
output [width-1:0] G;
|
|
||||||
....
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
To write a test bench, one creates a new module that instantiates the
|
|
||||||
design under test (DUT). The test bench declares nets and
|
|
||||||
regs (or signals in VHDL) that are attached to the DUT, and to
|
|
||||||
stimulus generators and response checkers. In an all-HDL flow, the
|
|
||||||
generators and checkers are written in the HDL itself, but we will
|
|
||||||
want to write them in \myhdl{}. To make the connection, we need to
|
|
||||||
declare which regs \& nets are driven and read by the \myhdl\
|
|
||||||
simulator. For our example, this is done as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
module dut_bin2gray;
|
|
||||||
|
|
||||||
reg [`width-1:0] B;
|
|
||||||
wire [`width-1:0] G;
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
$from_myhdl(B);
|
|
||||||
$to_myhdl(G);
|
|
||||||
end
|
|
||||||
|
|
||||||
bin2gray dut (.B(B), .G(G));
|
|
||||||
defparam dut.width = `width;
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The \code{\$from_myhdl} task call declares which regs are driven by
|
|
||||||
\myhdl{}, and the \code{\$to_myhdl} task call which regs \& nets are read
|
|
||||||
by it. These tasks take an arbitrary number of arguments. They are
|
|
||||||
defined in a PLI module written in C and made available in a
|
|
||||||
simulator-dependent manner. In Icarus Verilog, the tasks are defined
|
|
||||||
in a \code{myhdl.vpi} module that is compiled from C source code.
|
|
||||||
|
|
||||||
\section{The \myhdl\ side \label{cosim-myhdl}}
|
|
||||||
|
|
||||||
\myhdl\ supports co-simulation by a \code{Cosimulation} object.
|
|
||||||
A \code{Cosimulation} object must know how to run a HDL simulation.
|
|
||||||
Therefore, the first argument to its constructor is a command string
|
|
||||||
to execute a simulation.
|
|
||||||
|
|
||||||
The way to generate and run an simulation executable is simulator
|
|
||||||
dependent. For example, in Icarus Verilog, a simulation executable
|
|
||||||
for our example can be obtained obtained by running the
|
|
||||||
\code{iverilog} compiler as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% iverilog -o bin2gray -Dwidth=4 bin2gray.v dut_bin2gray.v
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This generates a \code{bin2gray} executable for a parameter \code{width}
|
|
||||||
of 4, by compiling the contributing verilog files.
|
|
||||||
|
|
||||||
The simulation itself is run by the \code{vvp} command:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% vvp -m ./myhdl.vpi bin2gray
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This runs the \code{bin2gray} simulation, and specifies to use the
|
|
||||||
\code{myhdl.vpi} PLI module present in the current directory. (This is
|
|
||||||
just a command line usage example; actually simulating with the
|
|
||||||
\code{myhdl.vpi} module is only meaningful from a
|
|
||||||
\code{Cosimulation} object.)
|
|
||||||
|
|
||||||
We can use a \code{Cosimulation} object to provide a HDL
|
|
||||||
version of a design to the \myhdl\ simulator. Instead of a generator
|
|
||||||
function, we write a function that returns a \code{Cosimulation}
|
|
||||||
object. For our example and the Icarus Verilog simulator, this is done
|
|
||||||
as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
import os
|
|
||||||
|
|
||||||
from myhdl import Cosimulation
|
|
||||||
|
|
||||||
cmd = "iverilog -o bin2gray -Dwidth=%s bin2gray.v dut_bin2gray.v"
|
|
||||||
|
|
||||||
def bin2gray(B, G, width):
|
|
||||||
os.system(cmd % width)
|
|
||||||
return Cosimulation("vvp -m ./myhdl.vpi bin2gray", B=B, G=G)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
After the executable command argument, the \code{Cosimulation}
|
|
||||||
constructor takes an arbitrary number of keyword arguments. Those
|
|
||||||
arguments make the link between \myhdl\ Signals and HDL nets, regs, or
|
|
||||||
signals, by named association. The keyword is the name of an argument
|
|
||||||
in a \code{\$to_myhdl} or \code{\$from_myhdl} call; the argument is
|
|
||||||
a \myhdl\ Signal.
|
|
||||||
|
|
||||||
With all this in place, we can now use the existing unit test
|
|
||||||
to verify the Verilog implementation. Note that we kept the
|
|
||||||
same name and parameters for the the \code{bin2gray} function:
|
|
||||||
all we need to do is to provide this alternative definition
|
|
||||||
to the existing unit test.
|
|
||||||
|
|
||||||
Let's try it on the Verilog design:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
module bin2gray(B, G);
|
|
||||||
|
|
||||||
parameter width = 8;
|
|
||||||
input [width-1:0] B;
|
|
||||||
output [width-1:0] G;
|
|
||||||
reg [width-1:0] G;
|
|
||||||
integer i;
|
|
||||||
wire [width:0] extB;
|
|
||||||
|
|
||||||
assign extB = {1'b0, B}; // zero-extend input
|
|
||||||
|
|
||||||
always @(extB) begin
|
|
||||||
for (i=0; i < width; i=i+1)
|
|
||||||
G[i] <= extB[i+1] ^ extB[i];
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
When we run our unit test, we get:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python test_bin2gray.py
|
|
||||||
Check that only one bit changes in successive codewords ... ok
|
|
||||||
Check that all codewords occur exactly once ... ok
|
|
||||||
Check that the code is an original Gray code ... ok
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 3 tests in 2.729s
|
|
||||||
|
|
||||||
OK
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
\section{Restrictions \label{cosim-restr}}
|
|
||||||
|
|
||||||
In the ideal case, it should be possible to simulate
|
|
||||||
any HDL description seamlessly with \myhdl{}. Moreover
|
|
||||||
the communicating signals at each side should act
|
|
||||||
transparently as a single one, enabling fully race free
|
|
||||||
operation.
|
|
||||||
|
|
||||||
For various reasons, it may not be possible or desirable
|
|
||||||
to achieve full generality. As anyone that has developed
|
|
||||||
applications with the Verilog PLI can testify, the
|
|
||||||
restrictions in a particular simulator, and the
|
|
||||||
differences over various simulators, can be quite
|
|
||||||
frustrating. Moreover, full generality may require
|
|
||||||
a disproportionate amount of development work compared
|
|
||||||
to a slightly less general solution that may
|
|
||||||
be sufficient for the target application.
|
|
||||||
|
|
||||||
Consequently, I have tried to achieve a solution
|
|
||||||
which is simple enough so that one can reasonably
|
|
||||||
expect that any PLI-enabled simulator can support it,
|
|
||||||
and that is relatively easy to verify and maintain.
|
|
||||||
At the same time, the solution is sufficiently general
|
|
||||||
to cover the target application space.
|
|
||||||
|
|
||||||
The result is a compromise that places certain restrictions
|
|
||||||
on the HDL code. In this section, these restrictions
|
|
||||||
are presented.
|
|
||||||
|
|
||||||
\subsection{Only passive HDL can be co-simulated \label{cosim-pass}}
|
|
||||||
|
|
||||||
The most important restriction of the \myhdl\ co-simulation solution is
|
|
||||||
that only ``passive'' HDL can be co-simulated. This means that the HDL
|
|
||||||
code should not contain any statements with time delays. In other
|
|
||||||
words, the \myhdl\ simulator should be the master of time; in
|
|
||||||
particular, any clock signal should be generated at the \myhdl\ side.
|
|
||||||
|
|
||||||
At first this may seem like an important restriction, but if one
|
|
||||||
considers the target application for co-simulation, it probably
|
|
||||||
isn't.
|
|
||||||
|
|
||||||
\myhdl\ supports co-simulation so that test benches for HDL
|
|
||||||
designs can be written in Python. Let's consider the nature of the
|
|
||||||
target HDL designs. For high-level, behavioral models that are not
|
|
||||||
intended for implementation, it should come as no surprise that I
|
|
||||||
would recommend to write them in \myhdl\ directly; that is one of the
|
|
||||||
goals of the \myhdl\ effort. Likewise, gate level designs with
|
|
||||||
annotated timing are not the target application: static timing
|
|
||||||
analysis is a much better verification method for such designs.
|
|
||||||
|
|
||||||
Rather, the targeted HDL designs are naturally models that are
|
|
||||||
intended for implementation, most likely through synthesis. As time
|
|
||||||
delays are meaningless in synthesizable code, the restriction is
|
|
||||||
compatible with the target application.
|
|
||||||
|
|
||||||
\subsection{Race sensitivity issues \label{cosim-race}}
|
|
||||||
|
|
||||||
In a typical RTL code, some events cause other events to occur in the
|
|
||||||
same time step. For example, when a clock signal triggers some signals
|
|
||||||
may change in the same time step. For race-free operation, an HDL
|
|
||||||
must differentiate between such events within a time step. This is done
|
|
||||||
by the concept of ``delta'' cycles. In a fully general, race free
|
|
||||||
co-simulation, the co-simulators would communicate at the level of delta
|
|
||||||
cycles. However, in \myhdl\ co-simulation, this is not entirely the
|
|
||||||
case.
|
|
||||||
|
|
||||||
Delta cycles from the \myhdl\ simulator toward the HDL co-simulator are
|
|
||||||
preserved. However, in the opposite direction, they are not. The
|
|
||||||
signals changes are only returned to the \myhdl\ simulator after all delta
|
|
||||||
cycles have been performed in the HDL co-simulator.
|
|
||||||
|
|
||||||
What does this mean? Let's start with the good news. As explained in
|
|
||||||
the previous section, the concept behind \myhdl\ co-simulation implies
|
|
||||||
that clocks are generated at the \myhdl\ side. \emph{When using a
|
|
||||||
\myhdl\ clock and its corresponding HDL signal directly as a clock,
|
|
||||||
co-simulation is race free.} In other words, the case
|
|
||||||
that most closely reflects the \myhdl\ co-simulation approach, is race free.
|
|
||||||
|
|
||||||
The situation is different when you want to use a signal driven by the
|
|
||||||
HDL (and the corresponding MyHDL signal) as a clock.
|
|
||||||
Communication triggered by such a clock is not race free. The solution
|
|
||||||
is to treat such an interface as a chip interface instead of an RTL
|
|
||||||
interface. For example, when data is triggered at positive clock
|
|
||||||
edges, it can safely be sampled at negative clock edges.
|
|
||||||
Alternatively, the \myhdl\ data signals can be declared with a delay
|
|
||||||
value, so that they are guaranteed to change after the clock
|
|
||||||
edge.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Implementation notes \label{cosim-impl}}
|
|
||||||
|
|
||||||
\begin{quote}
|
|
||||||
\em
|
|
||||||
This section requires some knowledge of PLI terminology.
|
|
||||||
\end{quote}
|
|
||||||
|
|
||||||
Enabling a simulator for co-simulation requires a PLI module written
|
|
||||||
in C. In Verilog, the PLI is part of the ``standard''. However,
|
|
||||||
different simulators implement different versions and portions of the
|
|
||||||
standard. Worse yet, the behavior of certain PLI callbacks is not
|
|
||||||
defined on some essential points. As a result, one should plan to
|
|
||||||
write or at least customize a specific PLI module for any simulator.
|
|
||||||
The release contains a PLI module for the open source Icarus
|
|
||||||
and Cver simulators.
|
|
||||||
|
|
||||||
This section documents the current approach and status of the PLI
|
|
||||||
module implementation and some reflections on future
|
|
||||||
implementations.
|
|
||||||
|
|
||||||
\subsection{Icarus Verilog \label{cosim-icarus}}
|
|
||||||
|
|
||||||
\subsubsection{Delta cycle implementation \label{cosim-icarus-delta}}
|
|
||||||
|
|
||||||
To make co-simulation work, a specific type of PLI callback is
|
|
||||||
needed. The callback should be run when all pending events have been
|
|
||||||
processed, while allowing the creation of new events in the current
|
|
||||||
time step (e.g. by the \myhdl\ simulator). In some Verilog
|
|
||||||
simulators, the \code{cbReadWriteSync} callback does exactly
|
|
||||||
that. However, in others, including Icarus, it does not. The
|
|
||||||
callback's behavior is not fully standardized; some simulators run the
|
|
||||||
callback before non-blocking assignment events have been processed.
|
|
||||||
|
|
||||||
Consequently, I had to look for a workaround. One half of the solution
|
|
||||||
is to use the \code{cbReadOnlySync} callback. This callback runs
|
|
||||||
after all pending events have been processed. However, it does not
|
|
||||||
permit to create new events in the current time step. The second half
|
|
||||||
of the solution is to map \myhdl\ delta cycles onto real Verilog time
|
|
||||||
steps. Note that fortunately I had some freedom here because of the
|
|
||||||
restriction that only passive HDL code can be co-simulated.
|
|
||||||
|
|
||||||
I chose to make the time granularity in the Verilog simulator a 1000
|
|
||||||
times finer than in the \myhdl{} simulator. For each \myhdl\ time
|
|
||||||
step, 1000 Verilog time steps are available for \myhdl\ delta
|
|
||||||
cycles. In practice, only a few delta cycles per time step should be
|
|
||||||
needed. Exceeding this limit almost certainly indicates a design error;
|
|
||||||
the limit is checked at run-time. The factor 1000 also makes it
|
|
||||||
easy to distinguish ``real'' time from delta cycle time when printing
|
|
||||||
out the Verilog time.
|
|
||||||
|
|
||||||
\subsubsection{Passive Verilog check \label{cosim-icarus-pass}}
|
|
||||||
|
|
||||||
As explained before, co-simulated Verilog should not contain delay
|
|
||||||
statements. Ideally, there should be a run-time check to flag
|
|
||||||
non-compliant code. However, there is currently no such check in the
|
|
||||||
Icarus module.
|
|
||||||
|
|
||||||
The check can be written using the \code{cbNextSimTime} VPI callback
|
|
||||||
in Verilog. However, Icarus 0.7 doesn't support this callback. In the
|
|
||||||
meantime, support for it has been added to the Icarus development
|
|
||||||
branch. When Icarus 0.8 is released, a check will be added.
|
|
||||||
|
|
||||||
In the mean time, just don't do this. It may appear to ``work'' but it
|
|
||||||
really won't as events will be missed over the co-simulation
|
|
||||||
interface.
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Cver \label{cosim-cver}}
|
|
||||||
|
|
||||||
MyHDL co-simulation is supported with the open source Verilog
|
|
||||||
simulator Cver. The PLI module is based on the one for Icarus
|
|
||||||
and basically has the same functionality. Only some cosmetic
|
|
||||||
modifications were required.
|
|
||||||
|
|
||||||
\subsection{Other Verilog simulators \label{cosim-impl-verilog}}
|
|
||||||
|
|
||||||
The Icarus module is written with VPI calls, which are provided by the
|
|
||||||
most recent generation of the Verilog PLI. Some simulators may only
|
|
||||||
support TF/ACC calls, requiring a complete redesign of the interface
|
|
||||||
module.
|
|
||||||
|
|
||||||
If the simulator supports VPI, the Icarus module should be reusable to
|
|
||||||
a large extent. However, it may be possible to improve on it. The
|
|
||||||
workaround to support delta cycles described in
|
|
||||||
Section~\ref{cosim-icarus-delta} may not be necessary. In some
|
|
||||||
simulators, the \code{cbReadWriteSync} callback occurs after all
|
|
||||||
events (including non-blocking assignments) have been processed. In
|
|
||||||
that case, the functionality can be supported without a finer time
|
|
||||||
granularity in the Verilog simulator.
|
|
||||||
|
|
||||||
There are also Verilog standardization efforts underway to resolve the
|
|
||||||
ambiguity of the \code{cbReadWriteSync} callback. The solution will be
|
|
||||||
to introduce new, well defined callbacks. From reading some proposals,
|
|
||||||
I conclude that the \code{cbEndOfSimTime} callback would provide the
|
|
||||||
required functionality.
|
|
||||||
|
|
||||||
The MyHDL project currently has no access to commercial Verilog
|
|
||||||
simulators, so progress in co-simulation support depends on external
|
|
||||||
interest and participation. Users have reported that they are using
|
|
||||||
MyHDL co-simulation with the simulators from Aldec and Modelsim.
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Interrupted system calls \label{cosim-impl-syscalls}}
|
|
||||||
|
|
||||||
The PLI module uses \code{read} and \code{write} system calls to
|
|
||||||
communicate between the co-simulators. The implementation assumes that
|
|
||||||
these calls are restarted automatically by the operating system when
|
|
||||||
interrupted. This is apparently what happens on the Linux box on which
|
|
||||||
MyHDL is developed.
|
|
||||||
|
|
||||||
It is known how non-restarted interrupted system calls should be
|
|
||||||
handled, but currently such code cannot be tested on the MyHDL
|
|
||||||
development platform. Also, it is not clear whether this is still a
|
|
||||||
relevant issue with modern operating systems. Therefore, this issue
|
|
||||||
has not been addressed at this moment. However, assertions have been
|
|
||||||
included that should trigger when this situation occurs.
|
|
||||||
|
|
||||||
Whenever an assertion fires in the PLI module, please report it. The
|
|
||||||
same holds for Python exceptions that cannot be easily explained.
|
|
||||||
|
|
||||||
\subsection{VHDL \label{cosim-impl-vhdl}}
|
|
||||||
|
|
||||||
It would be nice to have an interface to VHDL simulators such as the
|
|
||||||
Modelsim VHDL simulator. This will require a PLI module using the
|
|
||||||
PLI of the VHDL simulator.
|
|
||||||
|
|
||||||
The MyHDL project currently has no access to commercial VHDL
|
|
||||||
simulators, so progress in co-simulation support will depend on
|
|
||||||
external interest and participation.
|
|
@ -1,555 +0,0 @@
|
|||||||
\chapter{Introduction to \myhdl\ \label{intro}}
|
|
||||||
|
|
||||||
\section{A basic \myhdl\ simulation \label{intro-basic}}
|
|
||||||
|
|
||||||
We will introduce \myhdl\ with a classic \code{Hello World} style
|
|
||||||
example. All example code can be found in the distribution directory
|
|
||||||
under \file{example/manual/}. Here are the contents of a \myhdl\
|
|
||||||
simulation script called \file{hello1.py}:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from myhdl import Signal, delay, always, now, Simulation
|
|
||||||
|
|
||||||
def HelloWorld():
|
|
||||||
|
|
||||||
interval = delay(10)
|
|
||||||
|
|
||||||
@always(interval)
|
|
||||||
def sayHello():
|
|
||||||
print "%s Hello World!" % now()
|
|
||||||
|
|
||||||
return sayHello
|
|
||||||
|
|
||||||
|
|
||||||
inst = HelloWorld()
|
|
||||||
sim = Simulation(inst)
|
|
||||||
sim.run(30)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
When we run this simulation, we get the following output:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python hello1.py
|
|
||||||
10 Hello World!
|
|
||||||
20 Hello World!
|
|
||||||
30 Hello World!
|
|
||||||
_SuspendSimulation: Simulated 30 timesteps
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The first line of the script imports a number of objects from the
|
|
||||||
\code{myhdl} package. In Python we can only use identifiers that are
|
|
||||||
literally defined in the source file
|
|
||||||
\footnote{The exception is the \samp{from module import *} syntax,
|
|
||||||
that imports all the symbols from a module. Although this is generally
|
|
||||||
considered bad practice, it can be tolerated for large modules that
|
|
||||||
export a lot of symbols. One may argue that
|
|
||||||
\code{myhdl} falls into that category.}.
|
|
||||||
|
|
||||||
Then, we define a function called \function{HelloWorld}. In MyHDL,
|
|
||||||
classic functions are used to model hardware modules. In particular,
|
|
||||||
the parameter list is used to define the interface. In this first
|
|
||||||
example, the interface is empty.
|
|
||||||
|
|
||||||
Inside the top level function we declare a local function called
|
|
||||||
\function{sayHello} that defines the desired behavior. This function
|
|
||||||
is decorated with an \function{always} decorator that has a delay
|
|
||||||
\index{decorator!\function{always}}
|
|
||||||
object as its parameter. The meaning is that the function will be
|
|
||||||
executed whenever the specified delay interval has expired.
|
|
||||||
|
|
||||||
Behind the curtains, the \function{always} decorator creates a Python
|
|
||||||
\emph{generator} and reuses the name of the decorated function for
|
|
||||||
it. Generators are the fundamental objects in MyHDL, and we will say
|
|
||||||
much more about them further on.
|
|
||||||
|
|
||||||
Finally, the top level function returns the local generator. This is
|
|
||||||
the simplest case of the basic MyHDL code pattern
|
|
||||||
to define the contents of a hardware module. We will describe the
|
|
||||||
general case further on.
|
|
||||||
|
|
||||||
In MyHDL, we create an \emph{instance} of a hardware module by calling
|
|
||||||
the corresponding function. In the example, variable \code{inst} refers
|
|
||||||
to an instance of \function{HelloWorld}. To simulate the instance, we
|
|
||||||
pass it as an argument to a \class{Simulation} object constructor. We
|
|
||||||
then run the simulation for the desired amount of timesteps.
|
|
||||||
|
|
||||||
\section{Signals, ports, and concurrency \label{intro-conc}}
|
|
||||||
|
|
||||||
In the previous section, we simulated a design with a single
|
|
||||||
generator and no concurrency. On the other hand, real hardware
|
|
||||||
descriptions are typically massively concurrent.
|
|
||||||
\myhdl\ supports this by allowing an
|
|
||||||
arbitrary number of concurrently running generators.
|
|
||||||
|
|
||||||
With concurrency comes the problem of deterministic
|
|
||||||
communication. Hardware languages use special objects to
|
|
||||||
support deterministic communication between concurrent code.
|
|
||||||
In particular, \myhdl\
|
|
||||||
has a \class{Signal} object which is roughly modeled after VHDL
|
|
||||||
signals.
|
|
||||||
|
|
||||||
We will demonstrate signals and concurrency
|
|
||||||
by extending and modifying our first example. We define two hardware
|
|
||||||
modules, one that drives a clock signal, and one that is sensitive
|
|
||||||
to a positive edge on a clock signal:
|
|
||||||
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from myhdl import Signal, delay, always, now, Simulation
|
|
||||||
|
|
||||||
|
|
||||||
def ClkDriver(clk):
|
|
||||||
|
|
||||||
halfPeriod = delay(10)
|
|
||||||
|
|
||||||
@always(halfPeriod)
|
|
||||||
def driveClk():
|
|
||||||
clk.next = not clk
|
|
||||||
|
|
||||||
return driveClk
|
|
||||||
|
|
||||||
|
|
||||||
def HelloWorld(clk):
|
|
||||||
|
|
||||||
@always(clk.posedge)
|
|
||||||
def sayHello():
|
|
||||||
print "%s Hello World!" % now()
|
|
||||||
|
|
||||||
return sayHello
|
|
||||||
|
|
||||||
|
|
||||||
clk = Signal(0)
|
|
||||||
clkdriver_inst = ClkDriver(clk)
|
|
||||||
hello_inst = HelloWorld(clk)
|
|
||||||
sim = Simulation(clkdriver_inst, hello_inst)
|
|
||||||
sim.run(50)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The clock driver function \function{ClkDriver} has a
|
|
||||||
clock signal as its parameter. This is how a
|
|
||||||
\emph{port} is modeled in MyHDL. The function
|
|
||||||
defines a generator
|
|
||||||
that continuously toggles a clock signal after a certain delay.
|
|
||||||
A new value of a signal is specified by assigning to its
|
|
||||||
\code{next} attribute. This is the \myhdl\ equivalent of
|
|
||||||
\index{VHDL!signal assignment}%
|
|
||||||
the VHDL signal assignment and the
|
|
||||||
\index{Verilog!non-blocking assignment}%
|
|
||||||
Verilog non-blocking assignment.
|
|
||||||
|
|
||||||
The \function{HelloWorld} function is modified from the
|
|
||||||
first example. It now also takes a clock signal as parameter.
|
|
||||||
Its generator is made sensitive to a rising
|
|
||||||
\index{wait!for a rising edge}%
|
|
||||||
edge of the clock signal. This is specified by the
|
|
||||||
\code{posedge} attribute of a signal. The edge
|
|
||||||
specifier is the argument of the \code{always}
|
|
||||||
decorator. As a result, the decorated function
|
|
||||||
will be executed on every rising clock edge.
|
|
||||||
|
|
||||||
The \code{clk} signal is constructed with an initial value
|
|
||||||
\code{0}. When creating an instance of each
|
|
||||||
hardware module, the same clock signal is passed as
|
|
||||||
the argument. The result is that the instances
|
|
||||||
are now connected through the clock signal.
|
|
||||||
The \class{Simulation} object is constructed with the
|
|
||||||
two instances.
|
|
||||||
|
|
||||||
When we run the simulation, we get:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python hello2.py
|
|
||||||
10 Hello World!
|
|
||||||
30 Hello World!
|
|
||||||
50 Hello World!
|
|
||||||
_SuspendSimulation: Simulated 50 timesteps
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
\section{Parameters and hierarchy \label{intro-hier}}
|
|
||||||
|
|
||||||
We have seen that MyHDL uses functions to model hardware
|
|
||||||
modules. We have also seen that ports are modeled by using
|
|
||||||
signals as parameters. To make designs reusable we will also
|
|
||||||
want to use other objects as parameters. For example, we can
|
|
||||||
change the clock generator function to make it more general
|
|
||||||
and reusable, by making the clock period parameterizable, as
|
|
||||||
follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from myhdl import Signal, delay, instance, always, now, Simulation
|
|
||||||
|
|
||||||
def ClkDriver(clk, period=20):
|
|
||||||
|
|
||||||
lowTime = int(period/2)
|
|
||||||
highTime = period - lowTime
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def driveClk():
|
|
||||||
while True:
|
|
||||||
yield delay(lowTime)
|
|
||||||
clk.next = 1
|
|
||||||
yield delay(highTime)
|
|
||||||
clk.next = 0
|
|
||||||
|
|
||||||
return driveClk
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
In addition to the clock signal, the clock
|
|
||||||
period is a parameter, with a default value of \code{20}.
|
|
||||||
|
|
||||||
As the low time of the clock may differ from the high time in case of
|
|
||||||
an odd period, we cannot use the \function{always} decorator with a
|
|
||||||
single delay value anymore. Instead, the \function{driveClk} function
|
|
||||||
is now a generator function with an explicit definition of the desired
|
|
||||||
behavior. It is decorated with the \function{instance} decorator.
|
|
||||||
\index{decorator!\function{instance}}
|
|
||||||
You can see that \function{driveClk} is a generator function
|
|
||||||
because it contains \code{yield} statements.
|
|
||||||
|
|
||||||
When a generator function is called, it returns a generator object.
|
|
||||||
This is basically what the \function{instance} decorator does. It
|
|
||||||
is less sophisticated than the \function{always} decorator,
|
|
||||||
but it can be used to create a generator from any local generator
|
|
||||||
function.
|
|
||||||
|
|
||||||
The \code{yield} statement is a general Python construct, but MyHDL
|
|
||||||
uses it in a dedicated way. In MyHDL, it has a similar meaning as the
|
|
||||||
wait statement in VHDL: the statement suspends execution of a
|
|
||||||
generator, and its clauses specify the conditions on which the
|
|
||||||
generator should wait before resuming. In this case, the generator
|
|
||||||
waits for a certain delay.
|
|
||||||
|
|
||||||
Note that to make sure that the generator runs ``forever'', we wrap its
|
|
||||||
behavior in a \code{while True} loop.
|
|
||||||
|
|
||||||
Similarly, we can define a general \function{Hello} function as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def Hello(clk, to="World!"):
|
|
||||||
|
|
||||||
@always(clk.posedge)
|
|
||||||
def sayHello():
|
|
||||||
print "%s Hello %s" % (now(), to)
|
|
||||||
|
|
||||||
return sayHello
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
We can create any number of instances by calling the functions with
|
|
||||||
the appropriate parameters. Hierarchy can be modeled by defining the
|
|
||||||
instances in a higher-level function, and returning them.
|
|
||||||
This pattern can be repeated for an arbitrary number of
|
|
||||||
hierarchical levels. Consequently, the general definition
|
|
||||||
of a \myhdl\ instance is recursive: an instance
|
|
||||||
\index{instance!defined}%
|
|
||||||
is either a sequence of instances, or a generator.
|
|
||||||
|
|
||||||
As an example, we will create a higher-level function with
|
|
||||||
four instances of the lower-level functions, and simulate it:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def greetings():
|
|
||||||
|
|
||||||
clk1 = Signal(0)
|
|
||||||
clk2 = Signal(0)
|
|
||||||
|
|
||||||
clkdriver_1 = ClkDriver(clk1) # positional and default association
|
|
||||||
clkdriver_2 = ClkDriver(clk=clk2, period=19) # named association
|
|
||||||
hello_1 = Hello(clk=clk1) # named and default association
|
|
||||||
hello_2 = Hello(to="MyHDL", clk=clk2) # named association
|
|
||||||
|
|
||||||
return clkdriver_1, clkdriver_2, hello_1, hello_2
|
|
||||||
|
|
||||||
|
|
||||||
inst = greetings()
|
|
||||||
sim = Simulation(inst)
|
|
||||||
sim.run(50)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
As in standard Python, positional or named parameter association can
|
|
||||||
be used in instantiations, or a mix of both\footnote{All positional
|
|
||||||
parameters have to go before any named parameter.}. All these styles
|
|
||||||
are demonstrated in the example above. Named association can be very
|
|
||||||
useful if there are a lot of parameters, as the argument order in the
|
|
||||||
call does not matter in that case.
|
|
||||||
|
|
||||||
The simulation produces the following output:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python greetings.py
|
|
||||||
9 Hello MyHDL
|
|
||||||
10 Hello World!
|
|
||||||
28 Hello MyHDL
|
|
||||||
30 Hello World!
|
|
||||||
47 Hello MyHDL
|
|
||||||
50 Hello World!
|
|
||||||
_SuspendSimulation: Simulated 50 timesteps
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
\begin{notice}[warning]
|
|
||||||
Some commonly used terminology has different meanings
|
|
||||||
in Python versus hardware design. Rather than artificially
|
|
||||||
changing terminology, I think it's best to keep it
|
|
||||||
and explicitly describing the differences.
|
|
||||||
|
|
||||||
A \dfn{module} in Python refers to all source code
|
|
||||||
in a particular file. A module can be reused by
|
|
||||||
other modules by importing. In hardware design,
|
|
||||||
\index{module!in Python versus hardware design}%
|
|
||||||
a module is a reusable block of hardware with
|
|
||||||
a well defined interface. It can be reused in
|
|
||||||
another module by \dfn{instantiating} it.
|
|
||||||
|
|
||||||
An \dfn{instance} in Python (and other object-oriented
|
|
||||||
languages) refers to the object created by a
|
|
||||||
\index{instance!in Python versus hardware design}%
|
|
||||||
class constructor. In hardware design, an instance
|
|
||||||
is a particular incarnation of a hardware module.
|
|
||||||
|
|
||||||
Normally, the meaning should be clear from
|
|
||||||
the context. Occasionally, I may qualify terms
|
|
||||||
with the words 'hardware' or '\myhdl{}' to
|
|
||||||
avoid ambiguity.
|
|
||||||
\end{notice}
|
|
||||||
|
|
||||||
|
|
||||||
\section{Bit oriented operations \label{intro-bit}}
|
|
||||||
|
|
||||||
Hardware design involves dealing with bits and bit-oriented
|
|
||||||
operations. The standard Python type \class{int} has most of the
|
|
||||||
desired features, but lacks support for indexing and slicing. For this
|
|
||||||
reason, \myhdl\ provides the \class{intbv} class. The name was chosen
|
|
||||||
to suggest an integer with bit vector flavor.
|
|
||||||
|
|
||||||
Class \class{intbv} works transparently with other
|
|
||||||
integer-like types. Like class \class{int}, it provides access to the
|
|
||||||
underlying two's complement representation for bitwise
|
|
||||||
operations. In addition, it is a mutable type that provides indexing
|
|
||||||
and slicing operations, and some additional bit-oriented support such
|
|
||||||
as concatenation.
|
|
||||||
|
|
||||||
\subsection{Bit indexing \label{intro-indexing}}
|
|
||||||
\index{bit indexing}
|
|
||||||
|
|
||||||
As an example, we will consider the design of a Gray encoder. The
|
|
||||||
following code is a Gray encoder modeled in \myhdl{}:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from myhdl import Signal, delay, Simulation, always_comb, instance, intbv, bin
|
|
||||||
|
|
||||||
def bin2gray(B, G, width):
|
|
||||||
""" Gray encoder.
|
|
||||||
|
|
||||||
B -- input intbv signal, binary encoded
|
|
||||||
G -- output intbv signal, gray encoded
|
|
||||||
width -- bit width
|
|
||||||
"""
|
|
||||||
|
|
||||||
@always_comb
|
|
||||||
def logic():
|
|
||||||
for i in range(width):
|
|
||||||
G.next[i] = B[i+1] ^ B[i]
|
|
||||||
|
|
||||||
return logic
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This code introduces a few new concepts. The string in triple quotes
|
|
||||||
at the start of the function is a \dfn{doc string}. This is standard
|
|
||||||
Python practice for structured documentation of code.
|
|
||||||
|
|
||||||
Furthermore, we introduce a third decorator: \function{always_comb}.
|
|
||||||
\index{decorator!\function{always_comb}}
|
|
||||||
It is used with a classic function and specifies that the
|
|
||||||
resulting generator should
|
|
||||||
\index{wait!for a signal value change}%
|
|
||||||
wait for a value change on any input signal. This is typically used to
|
|
||||||
describe
|
|
||||||
\index{combinatorial logic}%
|
|
||||||
combinatorial logic. The \function{always_comb} decorator
|
|
||||||
automatically infers which signals are used as inputs.
|
|
||||||
|
|
||||||
Finally, the code contains bit indexing operations and an exclusive-or
|
|
||||||
operator as required for a Gray encoder. By convention, the lsb of an
|
|
||||||
\class{intbv} object has index~\code{0}.
|
|
||||||
|
|
||||||
To verify the Gray encoder, we write a test bench that prints input
|
|
||||||
and output for all possible input values:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def testBench(width):
|
|
||||||
|
|
||||||
B = Signal(intbv(0))
|
|
||||||
G = Signal(intbv(0))
|
|
||||||
|
|
||||||
dut = bin2gray(B, G, width)
|
|
||||||
|
|
||||||
@instance
|
|
||||||
def stimulus():
|
|
||||||
for i in range(2**width):
|
|
||||||
B.next = intbv(i)
|
|
||||||
yield delay(10)
|
|
||||||
print "B: " + bin(B, width) + "| G: " + bin(G, width)
|
|
||||||
|
|
||||||
return dut, stimulus
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
We use the conversion function \code{bin} to get a binary
|
|
||||||
string representation of the signal values. This function is exported
|
|
||||||
by the \code{myhdl} package and supplements the standard Python
|
|
||||||
\code{hex} and \code{oct} conversion functions.
|
|
||||||
|
|
||||||
As a demonstration, we set up a simulation for a small width:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
sim = Simulation(testBench(width=3))
|
|
||||||
sim.run()
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The simulation produces the following output:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python bin2gray.py
|
|
||||||
B: 000 | G: 000
|
|
||||||
B: 001 | G: 001
|
|
||||||
B: 010 | G: 011
|
|
||||||
B: 011 | G: 010
|
|
||||||
B: 100 | G: 110
|
|
||||||
B: 101 | G: 111
|
|
||||||
B: 110 | G: 101
|
|
||||||
B: 111 | G: 100
|
|
||||||
StopSimulation: No more events
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
\subsection{Bit slicing \label{intro-slicing}}
|
|
||||||
\index{bit slicing}
|
|
||||||
|
|
||||||
For a change, we will use a traditional function as an example to illustrate
|
|
||||||
slicing. The following function calculates the HEC byte of an ATM
|
|
||||||
header.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from myhdl import intbv, concat
|
|
||||||
|
|
||||||
COSET = 0x55
|
|
||||||
|
|
||||||
def calculateHec(header):
|
|
||||||
""" Return hec for an ATM header, represented as an intbv.
|
|
||||||
|
|
||||||
The hec polynomial is 1 + x + x**2 + x**8.
|
|
||||||
"""
|
|
||||||
hec = intbv(0)
|
|
||||||
for bit in header[32:]:
|
|
||||||
hec[8:] = concat(hec[7:2],
|
|
||||||
bit ^ hec[1] ^ hec[7],
|
|
||||||
bit ^ hec[0] ^ hec[7],
|
|
||||||
bit ^ hec[7]
|
|
||||||
)
|
|
||||||
return hec ^ COSET
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The code shows how slicing access and assignment is supported on the
|
|
||||||
\class{intbv} data type. In accordance with the most common hardware
|
|
||||||
convention, and unlike standard Python, slicing ranges are
|
|
||||||
downward. The code also demonstrates concatenation of \class{intbv}
|
|
||||||
objects.
|
|
||||||
|
|
||||||
As in standard Python, the slicing range is half-open: the highest
|
|
||||||
index bit is not included. Unlike standard Python however, this index
|
|
||||||
corresponds to the \emph{leftmost} item. Both indices can be omitted
|
|
||||||
from the slice. If the leftmost index is omitted, the meaning is to
|
|
||||||
access ``all'' higher order bits. If the rightmost index is omitted,
|
|
||||||
it is \code{0} by default.
|
|
||||||
|
|
||||||
The half-openness of a slice may seem awkward at first, but it helps
|
|
||||||
to avoid one-off count issues in practice. For example, the slice
|
|
||||||
\code{hex[8:]} has exactly \code{8} bits. Likewise, the slice
|
|
||||||
\code{hex[7:2]} has \code{7-2=5} bits. You can think about it as
|
|
||||||
follows: for a slice \code{[i:j]}, only bits below index \code{i} are
|
|
||||||
included, and the bit with index \code{j} is the last bit included.
|
|
||||||
|
|
||||||
When an intbv object is sliced, a new intbv object is returned. This
|
|
||||||
new intbv object is always positive, even when the original object
|
|
||||||
was negative.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Some remarks on \myhdl\ and Python \label{intro-python}}
|
|
||||||
|
|
||||||
To conclude this introductory chapter, it is useful to stress that
|
|
||||||
\myhdl\ is not a language in itself. The underlying language is Python,
|
|
||||||
and \myhdl\ is implemented as a Python package called \code{myhdl}.
|
|
||||||
Moreover, it is a design goal to keep the \code{myhdl} package as
|
|
||||||
minimalistic as possible, so that \myhdl\ descriptions are very much
|
|
||||||
``pure Python''.
|
|
||||||
|
|
||||||
To have Python as the underlying language is significant in several
|
|
||||||
ways:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
|
|
||||||
\item Python is a very powerful high level language. This translates
|
|
||||||
into high productivity and elegant solutions to complex problems.
|
|
||||||
|
|
||||||
\item Python is continuously improved by some very clever
|
|
||||||
minds, supported by a large and fast growing user base. Python profits
|
|
||||||
fully from the open source development model.
|
|
||||||
|
|
||||||
\item Python comes with an extensive standard library. Some
|
|
||||||
functionality is likely to be of direct interest to \myhdl\ users:
|
|
||||||
examples include string handling, regular expressions, random number
|
|
||||||
generation, unit test support, operating system interfacing and GUI
|
|
||||||
development. In addition, there are modules for mathematics, database
|
|
||||||
connections, networking programming, internet data handling, and so
|
|
||||||
on.
|
|
||||||
|
|
||||||
\item Python has a powerful C extension model. All built-in types are
|
|
||||||
written with the same C API that is available for custom
|
|
||||||
extensions. To a module user, there is no difference between a
|
|
||||||
standard Python module and a C extension module --- except
|
|
||||||
performance. The typical Python development model is to prototype
|
|
||||||
everything in Python until the application is stable, and (only) then
|
|
||||||
rewrite performance critical modules in C if necessary.
|
|
||||||
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
|
|
||||||
\section{Summary and perspective \label{intro-summary}}
|
|
||||||
Here is an overview of what we have learned in this chapter:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item Generators are the basic building blocks of MyHDL models. They
|
|
||||||
provide the way to model massive concurrency and sensitiviy lists.
|
|
||||||
|
|
||||||
\item MyHDL provides decorators that create useful generators from local functions.
|
|
||||||
|
|
||||||
\item Hardware structure and hierarchy is described with classic Python functions.
|
|
||||||
|
|
||||||
\item \code{Signal} objects are used to communicate between concurrent generators.
|
|
||||||
|
|
||||||
\item \code{intbv} objects are used to describe bit-oriented operations.
|
|
||||||
|
|
||||||
\item A \code{Simulation} object is used to simulate MyHDL models.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
These concepts are sufficient to start describing and simulating MyHDL models.
|
|
||||||
|
|
||||||
However, there is much more to MyHDL. Here is an overview of what can
|
|
||||||
be learned from the following chapters:
|
|
||||||
|
|
||||||
\begin{itemize}
|
|
||||||
\item MyHDL supports sophisticated and high level modeling techniques.
|
|
||||||
This is described in Chapter~\ref{model}
|
|
||||||
|
|
||||||
\item MyHDL enables the use of modern software verfication techniques,
|
|
||||||
such as unit testing, on hardware designs. This is the topic of
|
|
||||||
Chapter~\ref{unittest}.
|
|
||||||
|
|
||||||
\item It is possible to co-simulate MyHDL models with other HDL
|
|
||||||
languages such as Verilog and VHDL. This is described in
|
|
||||||
Chapter~\ref{cosim}.
|
|
||||||
|
|
||||||
\item Last but not least, MyHDL models can be converted to
|
|
||||||
Verilog, providing a path to a silicon implementation. This
|
|
||||||
is the topic of Chapter~\ref{conv}.
|
|
||||||
\end{itemize}
|
|
@ -1,554 +0,0 @@
|
|||||||
\chapter{Reference \label{ref}}
|
|
||||||
|
|
||||||
|
|
||||||
\myhdl\ is implemented as a Python package called \code{myhdl}. This
|
|
||||||
chapter describes the objects that are exported by this package.
|
|
||||||
|
|
||||||
\section{Simulation \label{ref-sim}}
|
|
||||||
|
|
||||||
\subsection{The \class{Simulation} class \label{ref-simclass}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\begin{classdesc}{Simulation}{arg \optional{, arg \moreargs}}
|
|
||||||
Class to construct a new simulation. Each argument should be a
|
|
||||||
\myhdl\ instance. In \myhdl{}, an instance is recursively defined
|
|
||||||
as being either a sequence of instances, or a \myhdl\ generator, or a
|
|
||||||
Cosimulation object. See section~\ref{ref-gen} for the definition of
|
|
||||||
\myhdl\ generators and their interaction with a
|
|
||||||
\class{Simulation} object. See Section~\ref{ref-cosim}
|
|
||||||
for the \class{Cosimulation} object. At most one \class{Cosimulation}
|
|
||||||
object can be passed to a \class{Simulation} constructor.
|
|
||||||
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
A \class{Simulation} object has the following method:
|
|
||||||
|
|
||||||
\begin{methoddesc}[Simulation]{run}{\optional{duration}}
|
|
||||||
Run the simulation forever (by default) or for a specified duration.
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Simulation support functions\label{ref-simsupport}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\begin{funcdesc}{now}{}
|
|
||||||
Returns the current simulation time.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{excclassdesc}{StopSimulation}{}
|
|
||||||
Base exception that is caught by the \code{Simulation.run()} method to
|
|
||||||
stop a simulation.
|
|
||||||
\end{excclassdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Waveform tracing\label{ref-trace}}
|
|
||||||
|
|
||||||
|
|
||||||
\begin{funcdesc}{traceSignals}{func \optional{, *args} \optional{, **kwargs}}
|
|
||||||
Enables signal tracing to a VCD file for waveform viewing.
|
|
||||||
\var{func} is a function that returns an instance.
|
|
||||||
\function{traceSignals()} calls \var{func} under its control
|
|
||||||
and passes \var{*args} and \var{**kwargs} to the call. In this way, it
|
|
||||||
finds the hierarchy and the signals to be traced.
|
|
||||||
|
|
||||||
The return value is the same as would be returned by the call
|
|
||||||
\code{func(*args, **kwargs)}. The top-level instance name and the
|
|
||||||
basename of the VCD output filename is \code{func.func_name} by
|
|
||||||
default. If the VCD file exists already, it will be moved to a backup
|
|
||||||
file by attaching a timestamp to it, before creating the new file.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
The \code{traceSignals} callable has the following attribute:
|
|
||||||
|
|
||||||
\begin{memberdesc}[traceSignals]{name}
|
|
||||||
|
|
||||||
This attribute is used to overwrite the default top-level instance
|
|
||||||
name and the basename of the VCD output filename.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\section{Modeling \label{ref-model}}
|
|
||||||
|
|
||||||
\subsection{The \class{Signal} class \label{ref-sig}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\begin{classdesc}{Signal}{\optional{val=None} \optional{, delay=0}}
|
|
||||||
This class is used to construct a new signal and to initialize its
|
|
||||||
value to \var{val}. Optionally, a delay can be specified.
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
A \class{Signal} object has the following attributes:
|
|
||||||
|
|
||||||
\begin{memberdesc}[Signal]{posedge}
|
|
||||||
Attribute that represents the positive edge of a signal, to be
|
|
||||||
used in sensitivity lists.
|
|
||||||
\end{memberdesc}
|
|
||||||
\begin{memberdesc}[Signal]{negedge}
|
|
||||||
Attribute that represents the negative edge of a signal, to be
|
|
||||||
used in sensitivity lists.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\begin{memberdesc}[Signal]{next}
|
|
||||||
Read-write attribute that represents the next value of the signal.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\begin{memberdesc}[Signal]{val}
|
|
||||||
Read-only attribute that represents the current value of the signal.
|
|
||||||
|
|
||||||
This attribute is always available to access the current value;
|
|
||||||
however in many practical case it will not be needed. Whenever there
|
|
||||||
is no ambiguity, the Signal object's current value is used
|
|
||||||
implicitly. In particular, all Python's standard numeric, bit-wise,
|
|
||||||
logical and comparison operators are implemented on a Signal object by
|
|
||||||
delegating to its current value. The exception is augmented
|
|
||||||
assignment. These operators are not implemented as they would break
|
|
||||||
the rule that the current value should be a read-only attribute. In
|
|
||||||
addition, when a Signal object is assigned to the \code{next}
|
|
||||||
attribute of another Signal object, its current value is assigned
|
|
||||||
instead.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\begin{memberdesc}[Signal]{min}
|
|
||||||
Read-only attribute that is the minimum value (inclusive) of a
|
|
||||||
numeric signal, or \var{None} for no minimum.
|
|
||||||
\end{memberdesc}
|
|
||||||
\begin{memberdesc}[Signal]{max}
|
|
||||||
Read-only attribute that is the maximum value
|
|
||||||
(exclusive) of a numeric signal, or \var{None} for no
|
|
||||||
maximum.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\begin{memberdesc}[Signal]{driven}
|
|
||||||
Writable attribute that can be used to indicate that the signal
|
|
||||||
is supposed to be driven from the MyHDL code, and how it should
|
|
||||||
be declared in Verilog after conversion. The allowed values
|
|
||||||
are \code{'reg'} and \code{'wire'}.
|
|
||||||
|
|
||||||
This attribute is useful when the Verilog converter cannot
|
|
||||||
infer automatically whether and how a signal is driven. This
|
|
||||||
occurs when the signal is driven from user-defined Verilog code.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{\myhdl\ generators and trigger objects \label{ref-gen}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\myhdl\ generators are standard Python generators with specialized
|
|
||||||
\keyword{yield} statements. In hardware description languages, the equivalent
|
|
||||||
statements are called
|
|
||||||
\index{sensitivity list}%
|
|
||||||
\emph{sensitivity lists}. The general format
|
|
||||||
of \keyword{yield} statements in in \myhdl\ generators is:
|
|
||||||
|
|
||||||
\hspace{\leftmargin}\keyword{yield} \var{clause \optional{, clause ...}}
|
|
||||||
|
|
||||||
When a generator executes a \keyword{yield} statement, its
|
|
||||||
execution is suspended at that point. At the same time, each
|
|
||||||
\var{clause} is a \emph{trigger object} which defines the condition
|
|
||||||
upon which the generator should be resumed. However, per invocation of a
|
|
||||||
\keyword{yield} statement, the generator resumes exactly once,
|
|
||||||
regardless of the number of clauses. This happens on the
|
|
||||||
first trigger that occurs.
|
|
||||||
|
|
||||||
In this section, the trigger objects and their functionality will be
|
|
||||||
described.
|
|
||||||
|
|
||||||
Some MyHDL objects that are described elsewhere can directly be used
|
|
||||||
as trigger objects. In particular, a signal can be used as
|
|
||||||
a trigger object. Whenever a signal changes value, the generator
|
|
||||||
resumes. Likewise, the objects referred to by the signal attributes
|
|
||||||
\code{posedge} and \code{negedge} are trigger objects. The generator
|
|
||||||
resumes on the occurrence of a positive or a negative edge on the
|
|
||||||
signal, respectively. An edge occurs when there is a change from
|
|
||||||
false to true (positive) or vice versa (negative).
|
|
||||||
For the full description of the \class{Signal} class and its
|
|
||||||
attributes, see section~\ref{ref-sig}.
|
|
||||||
|
|
||||||
Furthermore, \myhdl\ generators can be used as clauses in \code{yield}
|
|
||||||
statements. Such a generator is forked, and starts operating
|
|
||||||
immediately, while the original generator
|
|
||||||
waits for it to complete. The original generator resumes when the
|
|
||||||
forked generator returns.
|
|
||||||
|
|
||||||
|
|
||||||
In addition, the following functions return trigger objects:
|
|
||||||
|
|
||||||
\begin{funcdesc}{delay}{t}
|
|
||||||
Return a trigger object that specifies that the generator should
|
|
||||||
resume after a delay \var{t}.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{join}{arg \optional{, arg \moreargs}}
|
|
||||||
Join a number of trigger objects together and return a joined
|
|
||||||
trigger object. The effect is that the joined trigger object will
|
|
||||||
trigger when \emph{all} of its arguments have triggered.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
Finally, as a special case, the Python \code{None} object can be
|
|
||||||
present in a \code{yield} statement. It is the do-nothing
|
|
||||||
trigger object. The generator immediately resumes, as if no
|
|
||||||
\code{yield} statement were present. This can be useful if the
|
|
||||||
\code{yield} statement also has generator clauses: those generators
|
|
||||||
are forked, while the original generator resumes immediately.
|
|
||||||
|
|
||||||
\subsection{Decorator functions \label{ref-deco}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
MyHDL defines a number of decorator functions, that make it easier to
|
|
||||||
create generators from local generator functions.
|
|
||||||
|
|
||||||
\begin{funcdesc}{instance}{}
|
|
||||||
The \function{instance} decorator is the most general decorator. It
|
|
||||||
automatically creates a generator by calling the decorated generator function.
|
|
||||||
|
|
||||||
It is used as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def top(...):
|
|
||||||
...
|
|
||||||
@instance
|
|
||||||
def inst():
|
|
||||||
<generator body>
|
|
||||||
...
|
|
||||||
return inst, ...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This is equivalent to:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def top(...):
|
|
||||||
...
|
|
||||||
def _gen_func():
|
|
||||||
<generator body>
|
|
||||||
...
|
|
||||||
inst = _gen_func()
|
|
||||||
...
|
|
||||||
return inst, ...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\begin{funcdesc}{always}{arg \optional{, *args}}
|
|
||||||
|
|
||||||
The \function{always} decorator is a specialized decorator that targets a widely used
|
|
||||||
coding pattern. It is used as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def top(...):
|
|
||||||
...
|
|
||||||
@always(event1, event2, ...)
|
|
||||||
def inst()
|
|
||||||
<body>
|
|
||||||
...
|
|
||||||
return inst, ...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This is equivalent to the following:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def top(...):
|
|
||||||
...
|
|
||||||
def _func():
|
|
||||||
<body>
|
|
||||||
|
|
||||||
def _gen_func()
|
|
||||||
while True:
|
|
||||||
yield event1, event2, ...
|
|
||||||
_func()
|
|
||||||
...
|
|
||||||
inst = _gen_func()
|
|
||||||
...
|
|
||||||
return inst, ...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
The argument list of the decorator corresponds to the sensitivity
|
|
||||||
list. Only signals, edge specifiers, or delay objects are allowed.
|
|
||||||
The decorated function should be a classic function.
|
|
||||||
|
|
||||||
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\begin{funcdesc}{always_comb}{}
|
|
||||||
|
|
||||||
|
|
||||||
The \function{always_comb} decorator is used to describe combinatorial
|
|
||||||
logic.
|
|
||||||
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def top(...):
|
|
||||||
...
|
|
||||||
@always_comb
|
|
||||||
def comb_inst():
|
|
||||||
<combinatorial body>
|
|
||||||
...
|
|
||||||
return comb_inst, ...
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
The \function{always_comb} decorator infers the inputs of the combinatorial
|
|
||||||
logic and the corresponding sensitivity list automatically.
|
|
||||||
The decorated function should be a classic function.
|
|
||||||
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{The \class{intbv} class \label{ref-intbv}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\begin{classdesc}{intbv}{\optional{val=None} \optional{, min=None}
|
|
||||||
\optional{, max=None}}
|
|
||||||
This class represents \class{int}-like objects with some additional
|
|
||||||
features that make it suitable for hardware design. The \var{val}
|
|
||||||
argument can be an \class{int}, a \class{long}, an \class{intbv} or a
|
|
||||||
bit string (a string with only '0's or '1's). For a bit string
|
|
||||||
argument, the value is calculated as in \code{int(\var{bitstring},
|
|
||||||
2)}. The optional \var{min} and \var{max} arguments can be used to
|
|
||||||
specify the minimum and maximum value of the \class{intbv} object. As
|
|
||||||
in standard Python practice for ranges, the minimum value is inclusive
|
|
||||||
and the maximum value is exclusive.
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
The minimum and maximum values of an \class{intbv} object
|
|
||||||
are available as attributes:
|
|
||||||
|
|
||||||
\begin{memberdesc}[intbv]{min}
|
|
||||||
Read-only attribute that is the minimum value (inclusive) of an
|
|
||||||
\class{intbv}, or \var{None} for no minimum.
|
|
||||||
\end{memberdesc}
|
|
||||||
\begin{memberdesc}[intbv]{max}
|
|
||||||
Read-only attribute that is the maximum value
|
|
||||||
(exclusive) of an \class{intbv}, or \var{None} for no
|
|
||||||
maximum.
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
Unlike \class{int} objects, \class{intbv} objects are mutable; this is
|
|
||||||
also the reason for their existence. Mutability is needed to support
|
|
||||||
assignment to indexes and slices, as is common in hardware design. For
|
|
||||||
the same reason, \class{intbv} is not a subclass from \class{int},
|
|
||||||
even though \class{int} provides most of the desired
|
|
||||||
functionality. (It is not possible to derive a mutable subtype from
|
|
||||||
an immutable base type.)
|
|
||||||
|
|
||||||
An \class{intbv} object supports the same comparison, numeric,
|
|
||||||
bitwise, logical, and conversion operations as \class{int} objects. See
|
|
||||||
\url{http://www.python.org/doc/current/lib/typesnumeric.html} for more
|
|
||||||
information on such operations. In all binary operations,
|
|
||||||
\class{intbv} objects can work together with \class{int} objects.
|
|
||||||
For mixed-type numeric operations, the result type is an \class{int}
|
|
||||||
or a \class{long}. For mixed-type bitwise operations, the result
|
|
||||||
type is an \class{intbv}.
|
|
||||||
|
|
||||||
In addition, \class{intbv} objects support indexing and slicing
|
|
||||||
operations:
|
|
||||||
|
|
||||||
\begin{tableiii}{clc}{code}{Operation}{Result}{Notes}
|
|
||||||
\lineiii{\var{bv}[\var{i}]}
|
|
||||||
{item \var{i} of \var{bv}}
|
|
||||||
{(1)}
|
|
||||||
\lineiii{\var{bv}[\var{i}] = \var{x}}
|
|
||||||
{item \var{i} of \var{bv} is replaced by \var{x}}
|
|
||||||
{(1)}
|
|
||||||
\lineiii{\var{bv}[\var{i}:\var{j}]}
|
|
||||||
{slice of \var{bv} from \var{i} downto \var{j}}
|
|
||||||
{(2)(3)}
|
|
||||||
\lineiii{\var{bv}[\var{i}:\var{j}] = \var{t}}
|
|
||||||
{slice of \var{bv} from \var{i} downto \var{j} is replaced
|
|
||||||
by \var{t}}
|
|
||||||
{(2)(4)}
|
|
||||||
\end{tableiii}
|
|
||||||
|
|
||||||
\begin{description}
|
|
||||||
\item[(1)] Indexing follows the most common hardware design
|
|
||||||
conventions: the lsb bit is the rightmost bit, and it has
|
|
||||||
index 0. This has the following desirable property: if the
|
|
||||||
\class{intbv} value is decomposed as a sum of powers of 2,
|
|
||||||
the bit with index \var{i} corresponds to the term
|
|
||||||
\code{2**i}.
|
|
||||||
|
|
||||||
\item[(2)] In contrast to standard Python sequencing conventions,
|
|
||||||
slicing range are downward. This is a consequence of the
|
|
||||||
indexing convention, combined with the common convention
|
|
||||||
that the most significant digits of a number are the
|
|
||||||
leftmost ones. The Python convention of half-open ranges is
|
|
||||||
followed: the bit with the highest index is not
|
|
||||||
included. However, it is the \emph{leftmost} bit in this
|
|
||||||
case. As in standard Python, this takes care of one-off
|
|
||||||
issues in many practical cases: in particular,
|
|
||||||
\code{bv[\var{i}:]} returns \var{i} bits;
|
|
||||||
\code{bv[\var{i}:\var{j}]} has \code{\var{i}-\var{j}}
|
|
||||||
bits. When the low index \var{j} is omitted, it defaults
|
|
||||||
to \code{0}. When the high index \var{i} is omitted, it
|
|
||||||
means ``all'' higher order bits.
|
|
||||||
|
|
||||||
\item[(3)] The object returned from a slicing access operation is always a
|
|
||||||
positive \class{intbv}; higher order bits are implicitly
|
|
||||||
assumed to be zero. The bit width is implicitly stored in
|
|
||||||
the return object, so that it can be used in concatenations
|
|
||||||
and as an iterator. In addition, for a bit width w, the
|
|
||||||
\var{min} and \var{max} attributes are implicitly set to
|
|
||||||
\code{0} and \code{2**w}, respectively.
|
|
||||||
|
|
||||||
\item[(4)] When setting a slice to a value, it is checked whether the
|
|
||||||
slice is wide enough.
|
|
||||||
\end{description}
|
|
||||||
|
|
||||||
In addition, an \class{intbv} object supports the iterator protocol. This
|
|
||||||
makes it possible to iterate over all its bits, from the high index to
|
|
||||||
index 0. This is only possible for \class{intbv} objects with a
|
|
||||||
defined bit width.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Miscellaneous modeling support functions\label{ref-model-misc}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\begin{funcdesc}{bin}{num \optional{, width}}
|
|
||||||
Returns a bit string representation. If the optional \var{width}
|
|
||||||
is provided, and if it is larger than the width of the default
|
|
||||||
representation, the bit string is padded with the sign bit.
|
|
||||||
|
|
||||||
This function complements the standard Python conversion functions
|
|
||||||
\code{hex} and \code{oct}. A binary string representation is often
|
|
||||||
useful in hardware design.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{concat}{base \optional{, arg \moreargs}}
|
|
||||||
Returns an \class{intbv} object formed by concatenating the arguments.
|
|
||||||
|
|
||||||
The following argument types are supported: \class{intbv} objects with
|
|
||||||
a defined bit width, \class{bool} objects, signals of the previous
|
|
||||||
objects, and bit strings. All these objects have a defined bit
|
|
||||||
width. The first argument \var{base} is special as it doesn't need to
|
|
||||||
have a defined bit width. In addition to the previously mentioned
|
|
||||||
objects, unsized \class{intbv}, \class{int} and \class{long} objects
|
|
||||||
are supported, as well as signals of such objects.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{downrange}{high \optional{, low=0}}
|
|
||||||
Generates a downward range list of integers.
|
|
||||||
|
|
||||||
This function is modeled after the standard \code{range} function, but
|
|
||||||
works in the downward direction. The returned interval is half-open,
|
|
||||||
with the \var{high} index not included. \var{low} is optional and
|
|
||||||
defaults to zero. This function is especially useful in conjunction
|
|
||||||
with the \class{intbv} class, that also works with downward indexing.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{enum}{arg \optional{, arg \moreargs} \optional{, encoding='binary'}}
|
|
||||||
Returns an enumeration type.
|
|
||||||
|
|
||||||
The arguments should be string literals that represent the desired
|
|
||||||
names of the enumeration type attributes. The returned type should be
|
|
||||||
assigned to a type name. For example:
|
|
||||||
\begin{verbatim}
|
|
||||||
t_EnumType = enum('ATTR_NAME_1', 'ATTR_NAME_2', ...)
|
|
||||||
\end{verbatim}
|
|
||||||
The enumeration type identifiers are available as attributes of
|
|
||||||
the type name, for example: \code{t_EnumType.ATTR_NAME_1}
|
|
||||||
|
|
||||||
The optional keyword argument \var{encoding} specifies the encoding
|
|
||||||
scheme used in Verilog output. The available encodings are \code{'binary'},
|
|
||||||
\code{'one_hot'}, and \code{'one_cold'}.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{instances}{}
|
|
||||||
Looks up all \myhdl\ instances in the local name space and returns them
|
|
||||||
in a list.
|
|
||||||
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\section{Co-simulation\label{ref-cosim}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\subsection{\myhdl\ \label{ref-cosim-myhdl}}
|
|
||||||
|
|
||||||
\begin{classdesc}{Cosimulation}{exe, **kwargs}
|
|
||||||
Class to construct a new Cosimulation object.
|
|
||||||
|
|
||||||
The \var{exe} argument is a command string to
|
|
||||||
execute an HDL simulation. The \var{kwargs} keyword
|
|
||||||
arguments provide a named association between signals
|
|
||||||
(regs \& nets) in the HDL simulator and signals in the
|
|
||||||
\myhdl\ simulator. Each keyword should be a name listed
|
|
||||||
in a \code{\$to_myhdl} or \code{\$from_myhdl} call in
|
|
||||||
the HDL code. Each argument should be a \class{Signal}
|
|
||||||
declared in the \myhdl\ code.
|
|
||||||
|
|
||||||
\end{classdesc}
|
|
||||||
|
|
||||||
\subsection{Verilog \label{ref-cosim-verilog}}
|
|
||||||
|
|
||||||
\begin{funcdesc}{\$to_myhdl}{arg, \optional{, arg \moreargs}}
|
|
||||||
Task that defines which signals (regs \& nets) should be
|
|
||||||
read by the \myhdl\ simulator.
|
|
||||||
This task should be called at the start of the simulation.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
\begin{funcdesc}{\$from_myhdl}{arg, \optional{, arg \moreargs}}
|
|
||||||
Task that defines which signals should be
|
|
||||||
driven by the \myhdl\ simulator. In Verilog, only regs
|
|
||||||
can be specified.
|
|
||||||
This task should be called at the start of the simulation.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{VHDL \label{ref-cosim-vhdl}}
|
|
||||||
|
|
||||||
Not implemented yet.
|
|
||||||
|
|
||||||
\section{Conversion to Verilog\label{ref-conv}}
|
|
||||||
\declaremodule{}{myhdl}
|
|
||||||
|
|
||||||
\subsection{Conversion \label{ref-conv-conv}}
|
|
||||||
|
|
||||||
\begin{funcdesc}{toVerilog}{func \optional{, *args} \optional{, **kwargs}}
|
|
||||||
Converts a \myhdl\ design instance to equivalent Verilog
|
|
||||||
code, and also generates a test bench to verify it.
|
|
||||||
\var{func} is a function that returns an instance.
|
|
||||||
\function{toVerilog()} calls \var{func} under its control
|
|
||||||
and passes \var{*args} and \var{**kwargs} to the call.
|
|
||||||
|
|
||||||
The return value is the same as would be returned by the call
|
|
||||||
\code{func(*args, **kwargs)}. It should be assigned
|
|
||||||
to an instance name.
|
|
||||||
|
|
||||||
The top-level instance name and the basename of the Verilog output
|
|
||||||
filename is \code{func.func_name} by default.
|
|
||||||
|
|
||||||
For more information about the restrictions on convertible
|
|
||||||
\myhdl\ code, see section~\ref{conv-subset} in
|
|
||||||
Chapter~\ref{conv}.
|
|
||||||
\end{funcdesc}
|
|
||||||
|
|
||||||
The \function{toVerilog} callable has the following attribute:
|
|
||||||
|
|
||||||
\begin{memberdesc}[toVerilog]{name}
|
|
||||||
|
|
||||||
This attribute is used to overwrite the default top-level instance
|
|
||||||
name and the basename of the Verilog output filename.
|
|
||||||
|
|
||||||
\end{memberdesc}
|
|
||||||
|
|
||||||
\subsection{User-defined Verilog code \label{ref-conv-user}}
|
|
||||||
|
|
||||||
A user can insert user-defined code in the Verilog output
|
|
||||||
by using the \code{__verilog__} hook.
|
|
||||||
|
|
||||||
\begin{datadesc}{__verilog__}
|
|
||||||
When defined within a function under elaboration, the
|
|
||||||
\code{__verilog__} hook variable specifies user-defined code that
|
|
||||||
should be used instead of converted code for that function. The
|
|
||||||
user-defined code should be a Python format string that uses keys to
|
|
||||||
refer to the variables that should be interpolated in the string. Any
|
|
||||||
variable in the function context can be referred to.
|
|
||||||
|
|
||||||
Note that this hook cannot be used inside generator functions or
|
|
||||||
decorated local functions, as these are not elaborated.
|
|
||||||
\end{datadesc}
|
|
Before Width: | Height: | Size: 8.9 KiB |
@ -1,379 +0,0 @@
|
|||||||
\chapter{Unit testing \label{unittest}}
|
|
||||||
|
|
||||||
\section{Introduction \label{unittest-intro}}
|
|
||||||
|
|
||||||
Many aspects in the design flow of modern digital hardware design can
|
|
||||||
be viewed as a special kind of software development. From that
|
|
||||||
viewpoint, it is a natural question whether advances in software
|
|
||||||
design techniques can not also be applied to hardware design.
|
|
||||||
|
|
||||||
One software design approach that gets a lot of attention recently is
|
|
||||||
\index{extreme programming}%
|
|
||||||
\emph{Extreme Programming} (XP). It is a fascinating set of techniques and
|
|
||||||
guidelines that often seems to go against the conventional wisdom. On
|
|
||||||
other occasions, XP just seems to emphasize the common sense, which
|
|
||||||
doesn't always coincide with common practice. For example, XP stresses
|
|
||||||
the importance of normal workweeks, if we are to have the
|
|
||||||
fresh mind needed for good software development.
|
|
||||||
|
|
||||||
It is not my intention nor qualification to present a tutorial on
|
|
||||||
Extreme Programming. Instead, in this section I will highlight one XP
|
|
||||||
concept which I think is very relevant to hardware design: the
|
|
||||||
importance and methodology of unit testing.
|
|
||||||
|
|
||||||
\section{The importance of unit tests \label{unittest-why}}
|
|
||||||
|
|
||||||
Unit testing is one of the corner stones of Extreme Programming. Other
|
|
||||||
XP concepts, such as collective ownership of code and continuous
|
|
||||||
refinement, are only possible by having unit tests. Moreover, XP
|
|
||||||
emphasizes that writing unit tests should be automated, that they should
|
|
||||||
test everything in every class, and that they should run perfectly all
|
|
||||||
the time.
|
|
||||||
|
|
||||||
I believe that these concepts apply directly to hardware design. In
|
|
||||||
addition, unit tests are a way to manage simulation time. For example,
|
|
||||||
a state machine that runs very slowly on infrequent events may be
|
|
||||||
impossible to verify at the system level, even on the fastest
|
|
||||||
simulator. On the other hand, it may be easy to verify it exhaustively
|
|
||||||
in a unit test, even on the slowest simulator.
|
|
||||||
|
|
||||||
It is clear that unit tests have compelling advantages. On the other
|
|
||||||
hand, if we need to test everything, we have to write
|
|
||||||
lots of unit tests. So it should be easy and pleasant
|
|
||||||
to create, manage and run them. Therefore, XP emphasizes the need for
|
|
||||||
a unit test framework that supports these tasks. In this chapter,
|
|
||||||
we will explore the use of the \code{unittest} module from
|
|
||||||
the standard Python library for creating unit tests for hardware
|
|
||||||
designs.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Unit test development \label{unittest-dev}}
|
|
||||||
|
|
||||||
In this section, we will informally explore the application of unit
|
|
||||||
test techniques to hardware design. We will do so by a (small)
|
|
||||||
example: testing a binary to Gray encoder as introduced in
|
|
||||||
section~\ref{intro-indexing}.
|
|
||||||
|
|
||||||
\subsection{Defining the requirements \label{unittest-req}}
|
|
||||||
|
|
||||||
We start by defining the requirements. For a Gray encoder, we want to
|
|
||||||
the output to comply with Gray code characteristics. Let's define a
|
|
||||||
\dfn{code} as a list of \dfn{codewords}, where a codeword is a bit
|
|
||||||
string. A code of order \code{n} has \code{2**n} codewords.
|
|
||||||
|
|
||||||
A well-known characteristic is the one that Gray codes are all about:
|
|
||||||
|
|
||||||
\newtheorem{reqGray}{Requirement}
|
|
||||||
\begin{reqGray}
|
|
||||||
Consecutive codewords in a Gray code should differ in a single bit.
|
|
||||||
\end{reqGray}
|
|
||||||
|
|
||||||
Is this sufficient? Not quite: suppose for example that an
|
|
||||||
implementation returns the lsb of each binary input. This would comply
|
|
||||||
with the requirement, but is obviously not what we want. Also, we don't
|
|
||||||
want the bit width of Gray codewords to exceed the bit width of the
|
|
||||||
binary codewords.
|
|
||||||
|
|
||||||
\begin{reqGray}
|
|
||||||
Each codeword in a Gray code of order n must occur exactly once in the
|
|
||||||
binary code of the same order.
|
|
||||||
\end{reqGray}
|
|
||||||
|
|
||||||
With the requirements written down we can proceed.
|
|
||||||
|
|
||||||
\subsection{Writing the test first \label{unittest-first}}
|
|
||||||
|
|
||||||
A fascinating guideline in the XP world is to write the unit test
|
|
||||||
first. That is, before implementing something, first write the test
|
|
||||||
that will verify it. This seems to go against our natural inclination,
|
|
||||||
and certainly against common practices. Many engineers like to
|
|
||||||
implement first and think about verification afterwards.
|
|
||||||
|
|
||||||
But if you think about it, it makes a lot of sense to deal with
|
|
||||||
verification first. Verification is about the requirements only --- so
|
|
||||||
your thoughts are not yet cluttered with implementation details. The
|
|
||||||
unit tests are an executable description of the requirements, so they
|
|
||||||
will be better understood and it will be very clear what needs to be
|
|
||||||
done. Consequently, the implementation should go smoother. Perhaps
|
|
||||||
most importantly, the test is available when you are done
|
|
||||||
implementing, and can be run anytime by anybody to verify changes.
|
|
||||||
|
|
||||||
Python has a standard \code{unittest} module that facilitates writing,
|
|
||||||
managing and running unit tests. With \code{unittest}, a test case is
|
|
||||||
written by creating a class that inherits from
|
|
||||||
\code{unittest.TestCase}. Individual tests are created by methods of
|
|
||||||
that class: all method names that start with \code{test} are
|
|
||||||
considered to be tests of the test case.
|
|
||||||
|
|
||||||
We will define a test case for the Gray code properties, and then
|
|
||||||
write a test for each of the requirements. The outline of the test
|
|
||||||
case class is as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
class TestGrayCodeProperties(TestCase):
|
|
||||||
|
|
||||||
def testSingleBitChange(self):
|
|
||||||
""" Check that only one bit changes in successive codewords """
|
|
||||||
....
|
|
||||||
|
|
||||||
|
|
||||||
def testUniqueCodeWords(self):
|
|
||||||
""" Check that all codewords occur exactly once """
|
|
||||||
....
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Each method will be a small test bench that tests a single
|
|
||||||
requirement. To write the tests, we don't need an implementation of
|
|
||||||
the Gray encoder, but we do need the interface of the design. We can
|
|
||||||
specify this by a dummy implementation, as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def bin2gray(B, G, width):
|
|
||||||
### NOT IMPLEMENTED YET! ###
|
|
||||||
yield None
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
For the first requirement, we will write a test bench that applies all
|
|
||||||
consecutive input numbers, and compares the current output with the
|
|
||||||
previous one for each input. Then we check that the difference is a
|
|
||||||
single bit. We will test all Gray codes up to a certain order
|
|
||||||
\code{MAX_WIDTH}.
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def testSingleBitChange(self):
|
|
||||||
""" Check that only one bit changes in successive codewords """
|
|
||||||
|
|
||||||
def test(B, G, width):
|
|
||||||
B.next = intbv(0)
|
|
||||||
yield delay(10)
|
|
||||||
for i in range(1, 2**width):
|
|
||||||
G_Z.next = G
|
|
||||||
B.next = intbv(i)
|
|
||||||
yield delay(10)
|
|
||||||
diffcode = bin(G ^ G_Z)
|
|
||||||
self.assertEqual(diffcode.count('1'), 1)
|
|
||||||
|
|
||||||
for width in range(1, MAX_WIDTH):
|
|
||||||
B = Signal(intbv(-1))
|
|
||||||
G = Signal(intbv(0))
|
|
||||||
G_Z = Signal(intbv(0))
|
|
||||||
dut = bin2gray(B, G, width)
|
|
||||||
check = test(B, G, width)
|
|
||||||
sim = Simulation(dut, check)
|
|
||||||
sim.run(quiet=1)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Note how the actual check is performed by a \code{self.assertEqual}
|
|
||||||
method, defined by the \code{unittest.TestCase} class.
|
|
||||||
|
|
||||||
Similarly, we write a test bench for the second requirement. Again, we
|
|
||||||
simulate all numbers, and put the result in a list. The requirement
|
|
||||||
implies that if we sort the result list, we should get a range of
|
|
||||||
numbers:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def testUniqueCodeWords(self):
|
|
||||||
""" Check that all codewords occur exactly once """
|
|
||||||
|
|
||||||
def test(B, G, width):
|
|
||||||
actual = []
|
|
||||||
for i in range(2**width):
|
|
||||||
B.next = intbv(i)
|
|
||||||
yield delay(10)
|
|
||||||
actual.append(int(G))
|
|
||||||
actual.sort()
|
|
||||||
expected = range(2**width)
|
|
||||||
self.assertEqual(actual, expected)
|
|
||||||
|
|
||||||
for width in range(1, MAX_WIDTH):
|
|
||||||
B = Signal(intbv(-1))
|
|
||||||
G = Signal(intbv(0))
|
|
||||||
dut = bin2gray(B, G, width)
|
|
||||||
check = test(B, G, width)
|
|
||||||
sim = Simulation(dut, check)
|
|
||||||
sim.run(quiet=1)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Test-driven implementation \label{unittest-impl}}
|
|
||||||
|
|
||||||
With the test written, we begin with the implementation. For
|
|
||||||
illustration purposes, we will intentionally write some incorrect
|
|
||||||
implementations to see how the test behaves.
|
|
||||||
|
|
||||||
The easiest way to run tests defined with the \code{unittest}
|
|
||||||
framework, is to put a call to its \code{main} method at the end of
|
|
||||||
the test module:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
unittest.main()
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Let's run the test using the dummy Gray encoder shown earlier:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python test_gray.py -v
|
|
||||||
Check that only one bit changes in successive codewords ... FAIL
|
|
||||||
Check that all codewords occur exactly once ... FAIL
|
|
||||||
<trace backs not shown>
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
As expected, this fails completely. Let us try an incorrect
|
|
||||||
implementation, that puts the lsb of in the input on the output:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def bin2gray(B, G, width):
|
|
||||||
### INCORRECT - DEMO PURPOSE ONLY! ###
|
|
||||||
|
|
||||||
@always_comb
|
|
||||||
def logic():
|
|
||||||
G.next = B[0]
|
|
||||||
|
|
||||||
return logic
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
Running the test produces:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python test_gray.py -v
|
|
||||||
Check that only one bit changes in successive codewords ... ok
|
|
||||||
Check that all codewords occur exactly once ... FAIL
|
|
||||||
|
|
||||||
======================================================================
|
|
||||||
FAIL: Check that all codewords occur exactly once
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "test_gray.py", line 109, in testUniqueCodeWords
|
|
||||||
sim.run(quiet=1)
|
|
||||||
...
|
|
||||||
File "test_gray.py", line 104, in test
|
|
||||||
self.assertEqual(actual, expected)
|
|
||||||
File "/usr/local/lib/python2.2/unittest.py", line 286, in failUnlessEqual
|
|
||||||
raise self.failureException, \
|
|
||||||
AssertionError: [0, 0, 1, 1] != [0, 1, 2, 3]
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 2 tests in 0.785s
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
Now the test passes the first requirement, as expected, but fails the
|
|
||||||
second one. After the test feedback, a full traceback is shown that
|
|
||||||
can help to debug the test output.
|
|
||||||
|
|
||||||
Finally, if we use the correct implementation as in
|
|
||||||
section~\ref{intro-indexing}, the output is:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python test_gray.py -v
|
|
||||||
Check that only one bit changes in successive codewords ... ok
|
|
||||||
Check that all codewords occur exactly once ... ok
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 2 tests in 6.364s
|
|
||||||
|
|
||||||
OK
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Changing requirements \label{unittest-change}}
|
|
||||||
|
|
||||||
In the previous section, we concentrated on the general requirements
|
|
||||||
of a Gray code. It is possible to specify these without specifying the
|
|
||||||
actual code. It is easy to see that there are several codes
|
|
||||||
that satisfy these requirements. In good XP style, we only tested
|
|
||||||
the requirements and nothing more.
|
|
||||||
|
|
||||||
It may be that more control is needed. For example, the requirement
|
|
||||||
may be for a particular code, instead of compliance with general
|
|
||||||
properties. As an illustration, we will show how to test for
|
|
||||||
\emph{the} original Gray code, which is one specific instance that
|
|
||||||
satisfies the requirements of the previous section. In this particular
|
|
||||||
case, this test will actually be easier than the previous one.
|
|
||||||
|
|
||||||
We denote the original Gray code of order \code{n} as \code{Ln}. Some
|
|
||||||
examples:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
L1 = ['0', '1']
|
|
||||||
L2 = ['00', '01', '11', '10']
|
|
||||||
L3 = ['000', '001', '011', '010', '110', '111', '101', 100']
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
It is possible to specify these codes by a recursive algorithm, as
|
|
||||||
follows:
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item L1 = ['0', '1']
|
|
||||||
\item Ln+1 can be obtained from Ln as follows. Create a new code Ln0 by
|
|
||||||
prefixing all codewords of Ln with '0'. Create another new code Ln1 by
|
|
||||||
prefixing all codewords of Ln with '1', and reversing their
|
|
||||||
order. Ln+1 is the concatenation of Ln0 and Ln1.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
Python is well-known for its elegant algorithmic
|
|
||||||
descriptions, and this is a good example. We can write the algorithm
|
|
||||||
in Python as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
def nextLn(Ln):
|
|
||||||
""" Return Gray code Ln+1, given Ln. """
|
|
||||||
Ln0 = ['0' + codeword for codeword in Ln]
|
|
||||||
Ln1 = ['1' + codeword for codeword in Ln]
|
|
||||||
Ln1.reverse()
|
|
||||||
return Ln0 + Ln1
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
The code \samp{['0' + codeword for ...]} is called a \dfn{list
|
|
||||||
comprehension}. It is a concise way to describe lists built by short
|
|
||||||
computations in a for loop.
|
|
||||||
|
|
||||||
The requirement is now that the output code matches the
|
|
||||||
expected code Ln. We use the \code{nextLn} function to compute the
|
|
||||||
expected result. The new test case code is as follows:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
class TestOriginalGrayCode(TestCase):
|
|
||||||
|
|
||||||
def testOriginalGrayCode(self):
|
|
||||||
""" Check that the code is an original Gray code """
|
|
||||||
|
|
||||||
Rn = []
|
|
||||||
|
|
||||||
def stimulus(B, G, n):
|
|
||||||
for i in range(2**n):
|
|
||||||
B.next = intbv(i)
|
|
||||||
yield delay(10)
|
|
||||||
Rn.append(bin(G, width=n))
|
|
||||||
|
|
||||||
Ln = ['0', '1'] # n == 1
|
|
||||||
for n in range(2, MAX_WIDTH):
|
|
||||||
Ln = nextLn(Ln)
|
|
||||||
del Rn[:]
|
|
||||||
B = Signal(intbv(-1))
|
|
||||||
G = Signal(intbv(0))
|
|
||||||
dut = bin2gray(B, G, n)
|
|
||||||
stim = stimulus(B, G, n)
|
|
||||||
sim = Simulation(dut, stim)
|
|
||||||
sim.run(quiet=1)
|
|
||||||
self.assertEqual(Ln, Rn)
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
As it happens, our implementation is apparently an original Gray code:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
% python test_gray.py -v TestOriginalGrayCode
|
|
||||||
Check that the code is an original Gray code ... ok
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Ran 1 tests in 3.091s
|
|
||||||
|
|
||||||
OK
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
%
|
|
||||||
% Change this to say a4paper instead of letterpaper if you want A4. These
|
|
||||||
% are the latex defaults.
|
|
||||||
%
|
|
||||||
\newcommand{\py@paper}{a4paper}
|
|
||||||
\newcommand{\py@ptsize}{11pt}
|
|
||||||
|
|
||||||
% These set up the fonts for the documents.
|
|
||||||
%
|
|
||||||
% The "times" package makes the default font the PostScript Times
|
|
||||||
% font, which makes for smaller PostScript and a font that more people
|
|
||||||
% like.
|
|
||||||
%
|
|
||||||
% The "avant" package causes the AvantGarde font to be used for
|
|
||||||
% sans-serif text, instead of the uglier Helvetica set up by the "times"
|
|
||||||
% package.
|
|
||||||
%
|
|
||||||
% \RequirePackage{times}\typeout{Using Times instead of Computer Modern.}
|
|
@ -1,18 +0,0 @@
|
|||||||
%
|
|
||||||
% Change this to say a4paper instead of letterpaper if you want A4. These
|
|
||||||
% are the latex defaults.
|
|
||||||
%
|
|
||||||
\newcommand{\py@paper}{letterpaper}
|
|
||||||
\newcommand{\py@ptsize}{10pt}
|
|
||||||
|
|
||||||
% These set up the fonts for the documents.
|
|
||||||
%
|
|
||||||
% The "times" package makes the default font the PostScript Times
|
|
||||||
% font, which makes for smaller PostScript and a font that more people
|
|
||||||
% like.
|
|
||||||
%
|
|
||||||
% The "avant" package causes the AvantGarde font to be used for
|
|
||||||
% sans-serif text, instead of the uglier Helvetica set up by the "times"
|
|
||||||
% package.
|
|
||||||
%
|
|
||||||
% \RequirePackage{times}\typeout{Using Times instead of Computer Modern.}
|
|
@ -1,95 +0,0 @@
|
|||||||
package SynopsisTable;
|
|
||||||
|
|
||||||
sub new{
|
|
||||||
return bless {names=>'', info=>{}, file=>''};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub declare{
|
|
||||||
my($self,$name,$key,$type) = @_;
|
|
||||||
if ($self->{names}) {
|
|
||||||
$self->{names} .= ",$name";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->{names} .= "$name";
|
|
||||||
}
|
|
||||||
$self->{info}{$name} = "$key,$type,";
|
|
||||||
}
|
|
||||||
|
|
||||||
# The 'file' attribute is used to store the filename of the node in which
|
|
||||||
# the table will be presented; this assumes that each table will be presented
|
|
||||||
# only once, which works for the current use of this object.
|
|
||||||
|
|
||||||
sub set_file{
|
|
||||||
my($self, $filename) = @_;
|
|
||||||
$self->{file} = "$filename";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_file{
|
|
||||||
my $self = shift;
|
|
||||||
return $self->{file};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_synopsis{
|
|
||||||
my($self,$name,$synopsis) = @_;
|
|
||||||
my($key,$type,$unused) = split ',', $self->{info}{$name}, 3;
|
|
||||||
$self->{info}{$name} = "$key,$type,$synopsis";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get{
|
|
||||||
my($self,$name) = @_;
|
|
||||||
return split /,/, $self->{info}{$name}, 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub show{
|
|
||||||
my $self = shift;
|
|
||||||
my $name;
|
|
||||||
print "names: ", $self->{names}, "\n\n";
|
|
||||||
foreach $name (split /,/, $self->{names}) {
|
|
||||||
my($key,$type,$synopsis) = $self->get($name);
|
|
||||||
print "$name($key) is $type: $synopsis\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub tohtml{
|
|
||||||
my $self = shift;
|
|
||||||
my $oddrow = 1;
|
|
||||||
my $data = "<table class='synopsistable' valign='baseline'>\n";
|
|
||||||
my $name;
|
|
||||||
foreach $name (split /,/, $self->{names}) {
|
|
||||||
my($key,$type,$synopsis) = $self->get($name);
|
|
||||||
my $link = "<a href='module-$key.html'>";
|
|
||||||
$synopsis =~ s/<tex2html_percent_mark>/%/g;
|
|
||||||
$synopsis =~ s/<tex2html_ampersand_mark>/\&/g;
|
|
||||||
$data .= (' <tr'
|
|
||||||
. ($oddrow ? " class='oddrow'>\n " : '>')
|
|
||||||
. "<td><b><tt class='module'>$link$name</a></tt></b></td>\n"
|
|
||||||
. " <td>\ </td>\n"
|
|
||||||
. " <td class='synopsis'>$synopsis</td></tr>\n");
|
|
||||||
$oddrow = !$oddrow;
|
|
||||||
}
|
|
||||||
$data .= "</table>\n";
|
|
||||||
$data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
package testSynopsisTable;
|
|
||||||
|
|
||||||
sub test{
|
|
||||||
# this little test is mostly to debug the stuff above, since this is
|
|
||||||
# my first Perl "object".
|
|
||||||
my $st = SynopsisTable->new();
|
|
||||||
$st->declare("sample", "sample", "standard");
|
|
||||||
$st->set_synopsis("sample", "This is a little synopsis....");
|
|
||||||
$st->declare("copy_reg", "copyreg", "standard");
|
|
||||||
$st->set_synopsis("copy_reg", "pickle support stuff");
|
|
||||||
$st->show();
|
|
||||||
|
|
||||||
print "\n\n";
|
|
||||||
|
|
||||||
my $st2 = SynopsisTable->new();
|
|
||||||
$st2->declare("st2module", "st2module", "built-in");
|
|
||||||
$st2->set_synopsis("st2module", "silly little synopsis");
|
|
||||||
$st2->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
1; # This must be the last line -- Perl is bogus!
|
|
@ -1,21 +0,0 @@
|
|||||||
# LaTeX2HTML support for distutils.sty.
|
|
||||||
|
|
||||||
package main;
|
|
||||||
|
|
||||||
sub do_cmd_command {
|
|
||||||
return use_wrappers(@_[0], '<code>', '</code>');
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_cmd_option {
|
|
||||||
return use_wrappers(@_[0], '<font face="sans-serif">', '</font>');
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_cmd_filevar {
|
|
||||||
return use_wrappers(@_[0], '<font face="sans-serif"><i>', '</i></font>');
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_cmd_XXX {
|
|
||||||
return use_wrappers(@_[0], '<b>** ', ' **</b>');
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,12 +0,0 @@
|
|||||||
# -*- perl -*-
|
|
||||||
#
|
|
||||||
# This implements the Python howto class. All it really needs to do it
|
|
||||||
# load the "python" style.
|
|
||||||
|
|
||||||
package main;
|
|
||||||
|
|
||||||
do_require_package("article");
|
|
||||||
do_require_package("alltt");
|
|
||||||
do_require_package("python");
|
|
||||||
|
|
||||||
1; # sheesh....
|
|
@ -1,12 +0,0 @@
|
|||||||
package main;
|
|
||||||
|
|
||||||
$USING_STYLES = 0;
|
|
||||||
$NO_NAVIGATION = 1;
|
|
||||||
$INDEX_COLUMNS = 1;
|
|
||||||
$MODULE_INDEX_COLUMNS = 1;
|
|
||||||
|
|
||||||
sub child_line {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
1; # stupid perl...
|
|
@ -1,672 +0,0 @@
|
|||||||
# LaTeX2HTML support base for use with Python documentation.
|
|
||||||
|
|
||||||
package main;
|
|
||||||
|
|
||||||
use L2hos;
|
|
||||||
|
|
||||||
$HTML_VERSION = 4.0;
|
|
||||||
|
|
||||||
$MAX_LINK_DEPTH = 2;
|
|
||||||
$ADDRESS = '';
|
|
||||||
|
|
||||||
$NO_FOOTNODE = 1;
|
|
||||||
$NUMBERED_FOOTNOTES = 1;
|
|
||||||
|
|
||||||
# Python documentation uses section numbers to support references to match
|
|
||||||
# in the printed and online versions.
|
|
||||||
#
|
|
||||||
$SHOW_SECTION_NUMBERS = 1;
|
|
||||||
|
|
||||||
$ICONSERVER = '.';
|
|
||||||
$IMAGE_TYPE = 'gif';
|
|
||||||
|
|
||||||
# Control where the navigation bars should show up:
|
|
||||||
$TOP_NAVIGATION = 1;
|
|
||||||
$BOTTOM_NAVIGATION = 1;
|
|
||||||
$AUTO_NAVIGATION = 0;
|
|
||||||
|
|
||||||
$BODYTEXT = '';
|
|
||||||
$CHILDLINE = "\n<p><hr>\n";
|
|
||||||
$VERBOSITY = 0;
|
|
||||||
|
|
||||||
# default # of columns for the indexes
|
|
||||||
$INDEX_COLUMNS = 2;
|
|
||||||
$MODULE_INDEX_COLUMNS = 4;
|
|
||||||
|
|
||||||
$HAVE_MODULE_INDEX = 0;
|
|
||||||
$HAVE_GENERAL_INDEX = 0;
|
|
||||||
$HAVE_TABLE_OF_CONTENTS = 0;
|
|
||||||
|
|
||||||
$AESOP_META_TYPE = 'information';
|
|
||||||
|
|
||||||
|
|
||||||
# A little painful, but lets us clean up the top level directory a little,
|
|
||||||
# and not be tied to the current directory (as far as I can tell). Testing
|
|
||||||
# an existing definition of $mydir is needed since it cannot be computed when
|
|
||||||
# run under mkhowto with recent versions of LaTeX2HTML, since this file is
|
|
||||||
# not read directly by LaTeX2HTML any more. mkhowto is required to prepend
|
|
||||||
# the required definition at the top of the actual input file.
|
|
||||||
#
|
|
||||||
if (!defined $mydir) {
|
|
||||||
use Cwd;
|
|
||||||
use File::Basename;
|
|
||||||
($myname, $mydir, $myext) = fileparse(__FILE__, '\..*');
|
|
||||||
chop $mydir; # remove trailing '/'
|
|
||||||
$mydir = getcwd() . "$dd$mydir"
|
|
||||||
unless $mydir =~ s|^/|/|;
|
|
||||||
}
|
|
||||||
$LATEX2HTMLSTYLES = "$mydir$envkey$LATEX2HTMLSTYLES";
|
|
||||||
push (@INC, $mydir);
|
|
||||||
|
|
||||||
($myrootname, $myrootdir, $myext) = fileparse($mydir, '\..*');
|
|
||||||
chop $myrootdir;
|
|
||||||
|
|
||||||
|
|
||||||
# Hackish way to get the appropriate paper-*/ directory into $TEXINPUTS;
|
|
||||||
# pass in the paper size (a4 or letter) as the environment variable PAPER
|
|
||||||
# to add the right directory. If not given, the current directory is
|
|
||||||
# added instead for use with HOWTO processing.
|
|
||||||
#
|
|
||||||
if (defined $ENV{'PAPER'}) {
|
|
||||||
$mytexinputs = "$myrootdir${dd}paper-$ENV{'PAPER'}$envkey";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$mytexinputs = getcwd() . $envkey;
|
|
||||||
}
|
|
||||||
$mytexinputs .= "$myrootdir${dd}texinputs";
|
|
||||||
|
|
||||||
|
|
||||||
# Change this variable to change the text added in "About this document...";
|
|
||||||
# this should be an absolute pathname to get it right.
|
|
||||||
#
|
|
||||||
$ABOUT_FILE = "$myrootdir${dd}html${dd}stdabout.dat";
|
|
||||||
|
|
||||||
|
|
||||||
sub custom_driver_hook {
|
|
||||||
#
|
|
||||||
# This adds the directory of the main input file to $TEXINPUTS; it
|
|
||||||
# seems to be sufficiently general that it should be fine for HOWTO
|
|
||||||
# processing.
|
|
||||||
#
|
|
||||||
my $file = $_[0];
|
|
||||||
my($jobname, $dir, $ext) = fileparse($file, '\..*');
|
|
||||||
$dir = L2hos->Make_directory_absolute($dir);
|
|
||||||
$dir =~ s/$dd$//;
|
|
||||||
$TEXINPUTS = "$dir$envkey$mytexinputs";
|
|
||||||
print "\nAdding $dir to \$TEXINPUTS\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$CUSTOM_BUTTONS = '';
|
|
||||||
|
|
||||||
sub make_nav_sectref($$) {
|
|
||||||
my($label, $title) = @_;
|
|
||||||
if ($title) {
|
|
||||||
if ($title =~ /\<[aA] /) {
|
|
||||||
$title =~ s/\<[aA] /<a class="sectref" /;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$title = "<span class=\"sectref\">$title</span>";
|
|
||||||
}
|
|
||||||
return "<b class=\"navlabel\">$label:</b> $title\n";
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
@my_icon_tags = ();
|
|
||||||
$my_icon_tags{'next'} = 'Next Page';
|
|
||||||
$my_icon_tags{'next_page'} = 'Next Page';
|
|
||||||
$my_icon_tags{'previous'} = 'Previous Page';
|
|
||||||
$my_icon_tags{'previous_page'} = 'Previous Page';
|
|
||||||
$my_icon_tags{'up'} = 'Up One Level';
|
|
||||||
$my_icon_tags{'contents'} = 'Contents';
|
|
||||||
$my_icon_tags{'index'} = 'Index';
|
|
||||||
$my_icon_tags{'modules'} = 'Module Index';
|
|
||||||
|
|
||||||
@my_icon_names = ();
|
|
||||||
$my_icon_names{'previous_page'} = 'previous';
|
|
||||||
$my_icon_names{'next_page'} = 'next';
|
|
||||||
|
|
||||||
sub get_my_icon($) {
|
|
||||||
my $name = $_[0];
|
|
||||||
my $text = $my_icon_tags{$name};
|
|
||||||
if ($my_icon_names{$name}) {
|
|
||||||
$name = $my_icon_names{$name};
|
|
||||||
}
|
|
||||||
if ($text eq '') {
|
|
||||||
$name = 'blank';
|
|
||||||
}
|
|
||||||
my $iconserver = ($ICONSERVER eq '.') ? '' : "$ICONSERVER/";
|
|
||||||
return "<img src='$iconserver$name.$IMAGE_TYPE'\n border='0'"
|
|
||||||
. " height='32' alt='$text' width='32'>";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub use_my_icon($) {
|
|
||||||
my $s = $_[0];
|
|
||||||
if ($s =~ /\<tex2html_([a-z_]+)_visible_mark\>/) {
|
|
||||||
my $r = get_my_icon($1);
|
|
||||||
$s =~ s/\<tex2html_[a-z_]+_visible_mark\>/$r/;
|
|
||||||
}
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub make_nav_panel() {
|
|
||||||
my $s;
|
|
||||||
my $BLANK_ICON = get_my_icon('blank');
|
|
||||||
$NEXT = $NEXT_TITLE ? use_my_icon("$NEXT") : $BLANK_ICON;
|
|
||||||
$UP = $UP_TITLE ? use_my_icon("$UP") : $BLANK_ICON;
|
|
||||||
$PREVIOUS = $PREVIOUS_TITLE ? use_my_icon("$PREVIOUS") : $BLANK_ICON;
|
|
||||||
$CONTENTS = use_my_icon("$CONTENTS");
|
|
||||||
$INDEX = $INDEX ? use_my_icon("$INDEX") : $BLANK_ICON;
|
|
||||||
if (!$CUSTOM_BUTTONS) {
|
|
||||||
$CUSTOM_BUTTONS = $BLANK_ICON;
|
|
||||||
}
|
|
||||||
$s = ('<table align="center" width="100%" cellpadding="0" cellspacing="2">'
|
|
||||||
. "\n<tr>"
|
|
||||||
# left-hand side
|
|
||||||
. "\n<td>$PREVIOUS</td>"
|
|
||||||
. "\n<td>$UP</td>"
|
|
||||||
. "\n<td>$NEXT</td>"
|
|
||||||
# title box
|
|
||||||
. "\n<td align=\"center\" width=\"100%\">$t_title</td>"
|
|
||||||
# right-hand side
|
|
||||||
. "\n<td>$CONTENTS</td>"
|
|
||||||
. "\n<td>$CUSTOM_BUTTONS</td>" # module index
|
|
||||||
. "\n<td>$INDEX</td>"
|
|
||||||
. "\n</tr></table>\n"
|
|
||||||
# textual navigation
|
|
||||||
. make_nav_sectref("Previous", $PREVIOUS_TITLE)
|
|
||||||
. make_nav_sectref("Up", $UP_TITLE)
|
|
||||||
. make_nav_sectref("Next", $NEXT_TITLE)
|
|
||||||
);
|
|
||||||
# remove these; they are unnecessary and cause errors from validation
|
|
||||||
$s =~ s/ NAME="tex2html\d+"\n */ /g;
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_child_links {
|
|
||||||
my $toc = add_real_child_links(@_);
|
|
||||||
$toc =~ s|\s*</[aA]>|</a>|g;
|
|
||||||
$toc =~ s/ NAME=\"tex2html\d+\"\s*href=/ href=/gi;
|
|
||||||
$toc =~ s|</UL>(\s*<BR>)?|</ul>|gi;
|
|
||||||
return $toc;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_version_text() {
|
|
||||||
if ($PACKAGE_VERSION ne '' && $t_date) {
|
|
||||||
return ("<span class=\"release-info\">"
|
|
||||||
. "Release $PACKAGE_VERSION$RELEASE_INFO,"
|
|
||||||
. " documentation updated on $t_date.</span>");
|
|
||||||
}
|
|
||||||
if ($PACKAGE_VERSION ne '') {
|
|
||||||
return ("<span class=\"release-info\">"
|
|
||||||
. "Release $PACKAGE_VERSION$RELEASE_INFO.</span>");
|
|
||||||
}
|
|
||||||
if ($t_date) {
|
|
||||||
return ("<span class=\"release-info\">Documentation released on "
|
|
||||||
. "$t_date.</span>");
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub top_navigation_panel() {
|
|
||||||
return "\n"
|
|
||||||
. make_nav_panel()
|
|
||||||
. "<br><hr>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub bot_navigation_panel() {
|
|
||||||
return "\n<p><hr>\n"
|
|
||||||
. make_nav_panel()
|
|
||||||
. "<hr>\n"
|
|
||||||
. get_version_text()
|
|
||||||
. "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_link {
|
|
||||||
# Returns a pair (iconic link, textual link)
|
|
||||||
my($icon, $current_file, @link) = @_;
|
|
||||||
my($dummy, $file, $title) = split($delim,
|
|
||||||
$section_info{join(' ',@link)});
|
|
||||||
if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) {
|
|
||||||
my $r = get_my_icon($1);
|
|
||||||
$icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/;
|
|
||||||
}
|
|
||||||
if ($title && ($file ne $current_file)) {
|
|
||||||
$title = purify($title);
|
|
||||||
$title = get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES);
|
|
||||||
return (make_href($file, $icon), make_href($file, "$title"))
|
|
||||||
}
|
|
||||||
elsif ($icon eq get_my_icon('up') && $EXTERNAL_UP_LINK) {
|
|
||||||
return (make_href($EXTERNAL_UP_LINK, $icon),
|
|
||||||
make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE"))
|
|
||||||
}
|
|
||||||
elsif ($icon eq get_my_icon('previous')
|
|
||||||
&& $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) {
|
|
||||||
return (make_href($EXTERNAL_PREV_LINK, $icon),
|
|
||||||
make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE"))
|
|
||||||
}
|
|
||||||
elsif ($icon eq get_my_icon('next')
|
|
||||||
&& $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) {
|
|
||||||
return (make_href($EXTERNAL_DOWN_LINK, $icon),
|
|
||||||
make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE"))
|
|
||||||
}
|
|
||||||
return (&inactive_img($icon), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_special_link($$$) {
|
|
||||||
my($icon, $file, $current_file) = @_;
|
|
||||||
if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) {
|
|
||||||
my $r = get_my_icon($1);
|
|
||||||
$icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/;
|
|
||||||
}
|
|
||||||
return (($file && ($file ne $current_file))
|
|
||||||
? make_href($file, $icon)
|
|
||||||
: undef)
|
|
||||||
}
|
|
||||||
|
|
||||||
# The img_tag() function seems only to be called with the parameter
|
|
||||||
# 'anchor_invisible_mark', which we want to turn into ''. Since
|
|
||||||
# replace_icon_marks() is the only interesting caller, and all it really
|
|
||||||
# does is call img_tag(), we can just define the hook alternative to be
|
|
||||||
# a no-op instead.
|
|
||||||
#
|
|
||||||
sub replace_icons_hook {}
|
|
||||||
|
|
||||||
sub do_cmd_arabic {
|
|
||||||
# get rid of that nasty <SPAN CLASS="arabic">...</SPAN>
|
|
||||||
my($ctr, $val, $id, $text) = &read_counter_value($_[0]);
|
|
||||||
return ($val ? farabic($val) : "0") . $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub gen_index_id($$) {
|
|
||||||
# this is used to ensure common index key generation and a stable sort
|
|
||||||
my($str, $extra) = @_;
|
|
||||||
sprintf('%s###%s%010d', $str, $extra, ++$global{'max_id'});
|
|
||||||
}
|
|
||||||
|
|
||||||
sub insert_index($$$$$) {
|
|
||||||
my($mark, $datafile, $columns, $letters, $prefix) = @_;
|
|
||||||
my $prog = "$myrootdir/tools/buildindex.py";
|
|
||||||
my $index;
|
|
||||||
if ($letters) {
|
|
||||||
$index = `$prog --columns $columns --letters $datafile`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$index = `$prog --columns $columns $datafile`;
|
|
||||||
}
|
|
||||||
if (!s/$mark/$prefix$index/) {
|
|
||||||
print "\nCould not locate index mark: $mark";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_idx() {
|
|
||||||
print "\nBuilding HTML for the index ...";
|
|
||||||
close(IDXFILE);
|
|
||||||
insert_index($idx_mark, 'index.dat', $INDEX_COLUMNS, 1, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$idx_module_mark = '<tex2html_idx_module_mark>';
|
|
||||||
$idx_module_title = 'Module Index';
|
|
||||||
|
|
||||||
sub add_module_idx() {
|
|
||||||
print "\nBuilding HTML for the module index ...";
|
|
||||||
my $key;
|
|
||||||
my $first = 1;
|
|
||||||
my $prevplat = '';
|
|
||||||
my $allthesame = 1;
|
|
||||||
my $prefix = '';
|
|
||||||
foreach $key (keys %Modules) {
|
|
||||||
$key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/$1/;
|
|
||||||
my $plat = "$ModulePlatforms{$key}";
|
|
||||||
$plat = ''
|
|
||||||
if ($plat eq $IGNORE_PLATFORM_ANNOTATION);
|
|
||||||
if (!$first) {
|
|
||||||
$allthesame = 0
|
|
||||||
if ($prevplat ne $plat);
|
|
||||||
}
|
|
||||||
else { $first = 0; }
|
|
||||||
$prevplat = $plat;
|
|
||||||
}
|
|
||||||
open(MODIDXFILE, '>modindex.dat') || die "\n$!\n";
|
|
||||||
foreach $key (keys %Modules) {
|
|
||||||
# dump the line in the data file; just use a dummy seqno field
|
|
||||||
my $nkey = $1;
|
|
||||||
my $moditem = "$Modules{$key}";
|
|
||||||
my $plat = '';
|
|
||||||
$key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/$1/;
|
|
||||||
if ($ModulePlatforms{$key} && !$allthesame) {
|
|
||||||
$plat = (" <em>(<span class=\"platform\">$ModulePlatforms{$key}"
|
|
||||||
. '</span>)</em>');
|
|
||||||
}
|
|
||||||
print MODIDXFILE $moditem . $IDXFILE_FIELD_SEP
|
|
||||||
. "<tt class=\"module\">$key</tt>$plat###\n";
|
|
||||||
}
|
|
||||||
close(MODIDXFILE);
|
|
||||||
|
|
||||||
if ($GLOBAL_MODULE_INDEX) {
|
|
||||||
$prefix = <<MODULE_INDEX_PREFIX;
|
|
||||||
|
|
||||||
<p> This index only lists modules documented in this manual.
|
|
||||||
The <em class="citetitle"><a href="$GLOBAL_MODULE_INDEX">Global Module
|
|
||||||
Index</a></em> lists all modules that are documented in this set
|
|
||||||
of manuals.</p>
|
|
||||||
MODULE_INDEX_PREFIX
|
|
||||||
}
|
|
||||||
if (!$allthesame) {
|
|
||||||
$prefix .= <<PLAT_DISCUSS;
|
|
||||||
|
|
||||||
<p> Some module names are followed by an annotation indicating what
|
|
||||||
platform they are available on.</p>
|
|
||||||
|
|
||||||
PLAT_DISCUSS
|
|
||||||
}
|
|
||||||
insert_index($idx_module_mark, 'modindex.dat', $MODULE_INDEX_COLUMNS, 0,
|
|
||||||
$prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
# replace both indexes as needed:
|
|
||||||
sub add_idx_hook {
|
|
||||||
add_idx() if (/$idx_mark/);
|
|
||||||
process_python_state();
|
|
||||||
if ($MODULE_INDEX_FILE) {
|
|
||||||
local ($_);
|
|
||||||
open(MYFILE, "<$MODULE_INDEX_FILE");
|
|
||||||
sysread(MYFILE, $_, 1024*1024);
|
|
||||||
close(MYFILE);
|
|
||||||
add_module_idx();
|
|
||||||
open(MYFILE,">$MODULE_INDEX_FILE");
|
|
||||||
print MYFILE $_;
|
|
||||||
close(MYFILE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# In addition to the standard stuff, add label to allow named node files and
|
|
||||||
# support suppression of the page complete (for HTML Help use).
|
|
||||||
sub do_cmd_tableofcontents {
|
|
||||||
local($_) = @_;
|
|
||||||
$TITLE = $toc_title;
|
|
||||||
$tocfile = $CURRENT_FILE;
|
|
||||||
my($closures, $reopens) = preserve_open_tags();
|
|
||||||
anchor_label('contents', $CURRENT_FILE, $_); # this is added
|
|
||||||
join('', "<BR>\n\\tableofchildlinks[off]", $closures
|
|
||||||
, make_section_heading($toc_title, 'H2'), $toc_mark
|
|
||||||
, $reopens, $_);
|
|
||||||
}
|
|
||||||
# In addition to the standard stuff, add label to allow named node files.
|
|
||||||
sub do_cmd_listoffigures {
|
|
||||||
local($_) = @_;
|
|
||||||
$TITLE = $lof_title;
|
|
||||||
$loffile = $CURRENT_FILE;
|
|
||||||
my($closures, $reopens) = preserve_open_tags();
|
|
||||||
anchor_label('lof', $CURRENT_FILE, $_); # this is added
|
|
||||||
join('', "<BR>\n", $closures
|
|
||||||
, make_section_heading($lof_title, 'H2'), $lof_mark
|
|
||||||
, $reopens, $_);
|
|
||||||
}
|
|
||||||
# In addition to the standard stuff, add label to allow named node files.
|
|
||||||
sub do_cmd_listoftables {
|
|
||||||
local($_) = @_;
|
|
||||||
$TITLE = $lot_title;
|
|
||||||
$lotfile = $CURRENT_FILE;
|
|
||||||
my($closures, $reopens) = preserve_open_tags();
|
|
||||||
anchor_label('lot', $CURRENT_FILE, $_); # this is added
|
|
||||||
join('', "<BR>\n", $closures
|
|
||||||
, make_section_heading($lot_title, 'H2'), $lot_mark
|
|
||||||
, $reopens, $_);
|
|
||||||
}
|
|
||||||
# In addition to the standard stuff, add label to allow named node files.
|
|
||||||
sub do_cmd_textohtmlinfopage {
|
|
||||||
local($_) = @_;
|
|
||||||
if ($INFO) { #
|
|
||||||
anchor_label("about",$CURRENT_FILE,$_); # this is added
|
|
||||||
} #
|
|
||||||
my $the_version = ''; # and the rest is
|
|
||||||
if ($t_date) { # mostly ours
|
|
||||||
$the_version = ",\n$t_date";
|
|
||||||
if ($PACKAGE_VERSION) {
|
|
||||||
$the_version .= ", Release $PACKAGE_VERSION$RELEASE_INFO";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my $about;
|
|
||||||
open(ABOUT, "<$ABOUT_FILE") || die "\n$!\n";
|
|
||||||
sysread(ABOUT, $about, 1024*1024);
|
|
||||||
close(ABOUT);
|
|
||||||
$_ = (($INFO == 1)
|
|
||||||
? join('',
|
|
||||||
$close_all,
|
|
||||||
"<strong>$t_title</strong>$the_version\n",
|
|
||||||
$about,
|
|
||||||
$open_all, $_)
|
|
||||||
: join('', $close_all, $INFO,"\n", $open_all, $_));
|
|
||||||
$_;
|
|
||||||
}
|
|
||||||
|
|
||||||
# $idx_mark will be replaced with the real index at the end
|
|
||||||
sub do_cmd_textohtmlindex {
|
|
||||||
local($_) = @_;
|
|
||||||
$TITLE = $idx_title;
|
|
||||||
$idxfile = $CURRENT_FILE;
|
|
||||||
if (%index_labels) { make_index_labels(); }
|
|
||||||
if (($SHORT_INDEX) && (%index_segment)) { make_preindex(); }
|
|
||||||
else { $preindex = ''; }
|
|
||||||
my $heading = make_section_heading($idx_title, 'h2') . $idx_mark;
|
|
||||||
my($pre, $post) = minimize_open_tags($heading);
|
|
||||||
anchor_label('genindex',$CURRENT_FILE,$_); # this is added
|
|
||||||
return "<br>\n" . $pre . $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
$MODULE_INDEX_FILE = '';
|
|
||||||
|
|
||||||
# $idx_module_mark will be replaced with the real index at the end
|
|
||||||
sub do_cmd_textohtmlmoduleindex {
|
|
||||||
local($_) = @_;
|
|
||||||
$TITLE = $idx_module_title;
|
|
||||||
anchor_label('modindex', $CURRENT_FILE, $_);
|
|
||||||
$MODULE_INDEX_FILE = "$CURRENT_FILE";
|
|
||||||
$_ = ('<p>' . make_section_heading($idx_module_title, 'h2')
|
|
||||||
. $idx_module_mark . $_);
|
|
||||||
return $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
# The bibliography and the index should be treated as separate
|
|
||||||
# sections in their own HTML files. The \bibliography{} command acts
|
|
||||||
# as a sectioning command that has the desired effect. But when the
|
|
||||||
# bibliography is constructed manually using the thebibliography
|
|
||||||
# environment, or when using the theindex environment it is not
|
|
||||||
# possible to use the normal sectioning mechanism. This subroutine
|
|
||||||
# inserts a \bibliography{} or a dummy \textohtmlindex command just
|
|
||||||
# before the appropriate environments to force sectioning.
|
|
||||||
|
|
||||||
# XXX This *assumes* that if there are two {theindex} environments,
|
|
||||||
# the first is the module index and the second is the standard
|
|
||||||
# index. This is sufficient for the current Python documentation,
|
|
||||||
# but that's about it.
|
|
||||||
|
|
||||||
sub add_bbl_and_idx_dummy_commands {
|
|
||||||
my $id = $global{'max_id'};
|
|
||||||
|
|
||||||
if (/[\\]tableofcontents/) {
|
|
||||||
$HAVE_TABLE_OF_CONTENTS = 1;
|
|
||||||
}
|
|
||||||
s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg;
|
|
||||||
s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo;
|
|
||||||
my(@parts) = split(/\\begin\s*$O\d+$C\s*theindex/);
|
|
||||||
if (scalar(@parts) == 3) {
|
|
||||||
# Be careful to re-write the string in place, since $_ is *not*
|
|
||||||
# returned explicity; *** nasty side-effect dependency! ***
|
|
||||||
print "\nadd_bbl_and_idx_dummy_commands ==> adding general index";
|
|
||||||
print "\nadd_bbl_and_idx_dummy_commands ==> adding module index";
|
|
||||||
my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex[\\s\\S]*)"
|
|
||||||
. "([\\\\]begin\\s*$O\\d+$C\\s*theindex)";
|
|
||||||
s/$rx/\\textohtmlmoduleindex $1 \\textohtmlindex $2/o;
|
|
||||||
# Add a button to the navigation areas:
|
|
||||||
$CUSTOM_BUTTONS .= ('<a href="modindex.html" title="Module Index">'
|
|
||||||
. get_my_icon('modules')
|
|
||||||
. '</a>');
|
|
||||||
$HAVE_MODULE_INDEX = 1;
|
|
||||||
$HAVE_GENERAL_INDEX = 1;
|
|
||||||
}
|
|
||||||
elsif (scalar(@parts) == 2) {
|
|
||||||
print "\nadd_bbl_and_idx_dummy_commands ==> adding general index";
|
|
||||||
my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex)";
|
|
||||||
s/$rx/\\textohtmlindex $1/o;
|
|
||||||
$HAVE_GENERAL_INDEX = 1;
|
|
||||||
}
|
|
||||||
elsif (scalar(@parts) == 1) {
|
|
||||||
print "\nadd_bbl_and_idx_dummy_commands ==> no index found";
|
|
||||||
$CUSTOM_BUTTONS .= get_my_icon('blank');
|
|
||||||
$global{'max_id'} = $id; # not sure why....
|
|
||||||
s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o;
|
|
||||||
s/[\\]printindex/\\textohtmlindex /o;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die "\n\nBad number of index environments!\n\n";
|
|
||||||
}
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
lib_add_bbl_and_idx_dummy_commands()
|
|
||||||
if defined(&lib_add_bbl_and_idx_dummy_commands);
|
|
||||||
}
|
|
||||||
|
|
||||||
# The bibliographic references, the appendices, the lists of figures
|
|
||||||
# and tables etc. must appear in the contents table at the same level
|
|
||||||
# as the outermost sectioning command. This subroutine finds what is
|
|
||||||
# the outermost level and sets the above to the same level;
|
|
||||||
|
|
||||||
sub set_depth_levels {
|
|
||||||
# Sets $outermost_level
|
|
||||||
my $level;
|
|
||||||
#RRM: do not alter user-set value for $MAX_SPLIT_DEPTH
|
|
||||||
foreach $level ("part", "chapter", "section", "subsection",
|
|
||||||
"subsubsection", "paragraph") {
|
|
||||||
last if (($outermost_level) = /\\($level)$delimiter_rx/);
|
|
||||||
}
|
|
||||||
$level = ($outermost_level ? $section_commands{$outermost_level} :
|
|
||||||
do {$outermost_level = 'section'; 3;});
|
|
||||||
|
|
||||||
#RRM: but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given
|
|
||||||
if ($REL_DEPTH && $MAX_SPLIT_DEPTH) {
|
|
||||||
$MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH;
|
|
||||||
} elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 };
|
|
||||||
|
|
||||||
%unnumbered_section_commands = ('tableofcontents' => $level,
|
|
||||||
'listoffigures' => $level,
|
|
||||||
'listoftables' => $level,
|
|
||||||
'bibliography' => $level,
|
|
||||||
'textohtmlindex' => $level,
|
|
||||||
'textohtmlmoduleindex' => $level);
|
|
||||||
$section_headings{'textohtmlmoduleindex'} = 'h1';
|
|
||||||
|
|
||||||
%section_commands = (%unnumbered_section_commands,
|
|
||||||
%section_commands);
|
|
||||||
|
|
||||||
make_sections_rx();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# This changes the markup used for {verbatim} environments, and is the
|
|
||||||
# best way I've found that ensures the <dl> goes on the outside of the
|
|
||||||
# <pre>...</pre>.
|
|
||||||
#
|
|
||||||
# Note that this *must* be done in the init file, not the python.perl
|
|
||||||
# style support file. The %declarations must be set before
|
|
||||||
# initialize() is called in the main LaTeX2HTML script (which happens
|
|
||||||
# before style files are loaded).
|
|
||||||
#
|
|
||||||
%declarations = ('preform' => '<div class="verbatim"><pre></pre></div>',
|
|
||||||
%declarations);
|
|
||||||
|
|
||||||
|
|
||||||
# This is added to get rid of the long comment that follows the
|
|
||||||
# doctype declaration; MSIE5 on NT4 SP4 barfs on it and drops the
|
|
||||||
# content of the page.
|
|
||||||
$MY_PARTIAL_HEADER = '';
|
|
||||||
sub make_head_and_body($$) {
|
|
||||||
my($title, $body) = @_;
|
|
||||||
$body = " $body" unless ($body eq '');
|
|
||||||
my $DTDcomment = '';
|
|
||||||
my($version, $isolanguage) = ($HTML_VERSION, 'EN');
|
|
||||||
my %isolanguages = ( 'english', 'EN' , 'USenglish', 'EN.US'
|
|
||||||
, 'original', 'EN' , 'german' , 'DE'
|
|
||||||
, 'austrian', 'DE.AT', 'french' , 'FR'
|
|
||||||
, 'spanish', 'ES');
|
|
||||||
$isolanguage = $isolanguages{$default_language};
|
|
||||||
$isolanguage = 'EN' unless $isolanguage;
|
|
||||||
$title = &purify($title,1);
|
|
||||||
eval("\$title = ". $default_title ) unless ($title);
|
|
||||||
|
|
||||||
# allow user-modification of the <TITLE> tag; thanks Dan Young
|
|
||||||
if (defined &custom_TITLE_hook) {
|
|
||||||
$title = &custom_TITLE_hook($title, $toc_sec_title);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included
|
|
||||||
$DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE\">\n";
|
|
||||||
} else {
|
|
||||||
$DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE//"
|
|
||||||
. ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . "\">\n";
|
|
||||||
}
|
|
||||||
if ($MY_PARTIAL_HEADER eq '') {
|
|
||||||
$STYLESHEET = $FILE.".css" unless $STYLESHEET;
|
|
||||||
$MY_PARTIAL_HEADER = join('',
|
|
||||||
($DOCTYPE ? $DTDcomment : ''),
|
|
||||||
"<html>\n<head>\n",
|
|
||||||
($BASE ? "<base href=\"$BASE\">\n" : ''),
|
|
||||||
"<link rel=\"STYLESHEET\" href=\"$STYLESHEET\" type='text/css'>\n",
|
|
||||||
($FAVORITES_ICON
|
|
||||||
? ('<link rel="SHORTCUT ICON" href="' . "$FAVORITES_ICON\">\n")
|
|
||||||
: ''),
|
|
||||||
($EXTERNAL_UP_LINK
|
|
||||||
? ('<link rel="start" href="' . "$EXTERNAL_UP_LINK\""
|
|
||||||
. ($EXTERNAL_UP_TITLE ? " title='$EXTERNAL_UP_TITLE'" : '')
|
|
||||||
. ">\n")
|
|
||||||
: ''),
|
|
||||||
"<link rel=\"first\" href=\"$FILE.html\"",
|
|
||||||
($t_title ? " title='$t_title'" : ''),
|
|
||||||
">\n",
|
|
||||||
($HAVE_TABLE_OF_CONTENTS
|
|
||||||
? ('<link rel="contents" href="contents.html" title="Contents">'
|
|
||||||
. ($HAVE_GENERAL_INDEX ? "\n" : ''))
|
|
||||||
: ''),
|
|
||||||
($HAVE_GENERAL_INDEX
|
|
||||||
? '<link rel="index" href="genindex.html" title="Index">' . "\n"
|
|
||||||
: ''),
|
|
||||||
# disable for now -- Mozilla doesn't do well with multiple indexes
|
|
||||||
# ($HAVE_MODULE_INDEX
|
|
||||||
# ? '<link rel="index" href="modindex.html" title="Module Index">'
|
|
||||||
# . "\n"
|
|
||||||
# : ''),
|
|
||||||
($INFO
|
|
||||||
# XXX We can do this with the Python tools since the About...
|
|
||||||
# page always gets copied to about.html, even when we use the
|
|
||||||
# generated node###.html page names. Won't work with the
|
|
||||||
# rest of the Python doc tools.
|
|
||||||
? ("<link rel='last' href='about.html'"
|
|
||||||
. " title='About this document...'>\n"
|
|
||||||
. "<link rel='help' href='about.html'"
|
|
||||||
. " title='About this document...'>\n")
|
|
||||||
: ''),
|
|
||||||
$more_links_mark,
|
|
||||||
"\n",
|
|
||||||
($CHARSET && $HTML_VERSION ge "2.1"
|
|
||||||
? ('<meta http-equiv="Content-Type" content="text/html; '
|
|
||||||
. "charset=$CHARSET\">\n")
|
|
||||||
: ''),
|
|
||||||
($AESOP_META_TYPE
|
|
||||||
? "<meta name='aesop' content='$AESOP_META_TYPE'>\n" : ''));
|
|
||||||
}
|
|
||||||
if (!$charset && $CHARSET) {
|
|
||||||
$charset = $CHARSET;
|
|
||||||
$charset =~ s/_/\-/go;
|
|
||||||
}
|
|
||||||
join('',
|
|
||||||
$MY_PARTIAL_HEADER,
|
|
||||||
&meta_information($title),
|
|
||||||
"<title>", $title, "</title>\n</head>\n<body$body>");
|
|
||||||
}
|
|
||||||
|
|
||||||
1; # This must be the last line
|
|
@ -1,67 +0,0 @@
|
|||||||
# LaTeX2HTML support for the ltxmarkup package. Doesn't do indexing.
|
|
||||||
|
|
||||||
package main;
|
|
||||||
|
|
||||||
|
|
||||||
sub ltx_next_argument{
|
|
||||||
my $param;
|
|
||||||
$param = missing_braces()
|
|
||||||
unless ((s/$next_pair_pr_rx/$param=$2;''/eo)
|
|
||||||
||(s/$next_pair_rx/$param=$2;''/eo));
|
|
||||||
return $param;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub do_cmd_macro{
|
|
||||||
local($_) = @_;
|
|
||||||
my $macro = ltx_next_argument();
|
|
||||||
return "<tt class='macro'>\$macro</tt>" . $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_cmd_env{
|
|
||||||
local($_) = @_;
|
|
||||||
my $env = ltx_next_argument();
|
|
||||||
return "<tt class='environment'>\$env</tt>" . $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ltx_process_params{
|
|
||||||
# Handle processing of \p and \op for parameter specifications for
|
|
||||||
# envdesc and macrodesc. It's done this way to avoid defining do_cmd_p()
|
|
||||||
# and do_cmd_op() functions, which would be interpreted outside the context
|
|
||||||
# in which these commands are legal, and cause LaTeX2HTML to think they're
|
|
||||||
# defined. This way, other uses of \p and \op are properly flagged as
|
|
||||||
# unknown macros.
|
|
||||||
my $s = @_[0];
|
|
||||||
$s =~ s%\\op<<(\d+)>>(.+)<<\1>>%<tt>[</tt><var>$2</var><tt>]</tt>%;
|
|
||||||
while ($s =~ /\\p<<(\d+)>>(.+)<<\1>>/) {
|
|
||||||
$s =~ s%\\p<<(\d+)>>(.+)<<\1>>%<tt>{</tt><var>$2</var><tt>}</tt>%;
|
|
||||||
}
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_env_macrodesc{
|
|
||||||
local($_) = @_;
|
|
||||||
my $macro = ltx_next_argument();
|
|
||||||
my $params = ltx_process_params(ltx_next_argument());
|
|
||||||
return "\n<dl class='macrodesc'>"
|
|
||||||
. "\n<dt><b><tt class='macro'>\$macro</tt></b>"
|
|
||||||
. "\n $params"
|
|
||||||
. "\n<dd>"
|
|
||||||
. $_
|
|
||||||
. "</dl>";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_env_envdesc{
|
|
||||||
local($_) = @_;
|
|
||||||
my $env = ltx_next_argument();
|
|
||||||
my $params = ltx_process_params(ltx_next_argument());
|
|
||||||
return "\n<dl class='envdesc'>"
|
|
||||||
. "\n<dt><tt>\begin{<b class='environment'>$env</b>}</tt>"
|
|
||||||
. "\n $params"
|
|
||||||
. "\n<br /><tt>\end{<b class='environment'>$env</b>}</tt>"
|
|
||||||
. "\n<dd>"
|
|
||||||
. $_
|
|
||||||
. "</dl>";
|
|
||||||
}
|
|
||||||
|
|
||||||
1; # Must end with this, because Perl is bogus.
|
|
@ -1,15 +0,0 @@
|
|||||||
# -*- perl -*-
|
|
||||||
#
|
|
||||||
# This implements the Python manual class. All it really needs to do it
|
|
||||||
# load the "python" style. The style code is not moved into the class code
|
|
||||||
# at this time, since we expect additional document class to be developed
|
|
||||||
# for the Python documentation in the future. Appropriate relocations will
|
|
||||||
# be made at that time.
|
|
||||||
|
|
||||||
package main;
|
|
||||||
|
|
||||||
do_require_package("report");
|
|
||||||
do_require_package("alltt");
|
|
||||||
do_require_package("python");
|
|
||||||
|
|
||||||
1; # sheesh....
|
|
@ -1,4 +0,0 @@
|
|||||||
# tex
|
|
||||||
|
|
||||||
TEXINPUTS=".:./texinputs:"
|
|
||||||
export TEXINPUTS
|
|
@ -1,9 +0,0 @@
|
|||||||
\author{Jan Decaluwe}
|
|
||||||
\authoraddress{
|
|
||||||
Email: \email{jan@jandecaluwe.com}
|
|
||||||
}
|
|
||||||
|
|
||||||
\date{May 1, 2006} % XXX update before release!
|
|
||||||
\release{0.5.1} % software release, not documentation
|
|
||||||
\setreleaseinfo{} % empty for final release
|
|
||||||
\setshortversion{0.5} % major.minor only for software
|
|
@ -1,2 +0,0 @@
|
|||||||
Copyright \copyright{} 2003-2006 Jan Decaluwe.
|
|
||||||
All rights reserved.
|
|
@ -1,33 +0,0 @@
|
|||||||
%
|
|
||||||
% LaTeX commands and macros needed for the two Distutils manuals,
|
|
||||||
% inst.tex and dist.tex.
|
|
||||||
%
|
|
||||||
% $Id$
|
|
||||||
%
|
|
||||||
|
|
||||||
% My gripe list about the Python style files:
|
|
||||||
% * I want italics in verbatim environments for variable
|
|
||||||
% text (verbatim.sty?)
|
|
||||||
% * I hate escaping underscores (url.sty fixes this)
|
|
||||||
|
|
||||||
% '\command' is for Distutils commands which, depending on your
|
|
||||||
% perspective, are just arguments to the setup script, or sub-
|
|
||||||
% commands of the setup script, or the classes that implement
|
|
||||||
% each "command".
|
|
||||||
\newcommand{\command}[1]{\code{#1}}
|
|
||||||
|
|
||||||
% '\option' is for Distutils options *in* the setup script. Command-
|
|
||||||
% line options *to* the setup script are marked up in the usual
|
|
||||||
% way, ie. with '\programopt' or '\longprogramopt'
|
|
||||||
\newcommand{\option}[1]{\textsf{\small{#1}}}
|
|
||||||
|
|
||||||
% '\filevar' is for variable components of file/path names -- eg.
|
|
||||||
% when you put 'prefix' in a pathname, you mark it up with
|
|
||||||
% '\filevar' so that it still looks pathname-ish, but is
|
|
||||||
% distinguished from the literal part of the path. Fred says
|
|
||||||
% this can be accomplished just fine with '\var', but I violently
|
|
||||||
% disagree. Pistols at dawn will sort this one out.
|
|
||||||
\newcommand{\filevar}[1]{{\textsl{\filenq{#1}}}}
|
|
||||||
|
|
||||||
% Just while the code and docs are still under development.
|
|
||||||
\newcommand{\XXX}[1]{\textbf{**#1**}}
|
|
@ -1,329 +0,0 @@
|
|||||||
% fancyhdr.sty version 1.99d
|
|
||||||
% Fancy headers and footers for LaTeX.
|
|
||||||
% Piet van Oostrum, Dept of Computer Science, University of Utrecht
|
|
||||||
% Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands
|
|
||||||
% Telephone: +31 30 2532180. Email: piet@cs.ruu.nl
|
|
||||||
% ========================================================================
|
|
||||||
% LICENCE: This is free software. You are allowed to use and distribute
|
|
||||||
% this software in any way you like. You are also allowed to make modified
|
|
||||||
% versions of it, but you can distribute a modified version only if you
|
|
||||||
% clearly indicate that it is a modified version and the person(s) who
|
|
||||||
% modified it. This indication should be in a prominent place, e.g. in the
|
|
||||||
% top of the file. If possible a contact address, preferably by email,
|
|
||||||
% should be given for these persons. If that is feasible the modifications
|
|
||||||
% should be indicated in the source code.
|
|
||||||
% ========================================================================
|
|
||||||
% MODIFICATION HISTORY:
|
|
||||||
% Sep 16, 1994
|
|
||||||
% version 1.4: Correction for use with \reversemargin
|
|
||||||
% Sep 29, 1994:
|
|
||||||
% version 1.5: Added the \iftopfloat, \ifbotfloat and \iffloatpage commands
|
|
||||||
% Oct 4, 1994:
|
|
||||||
% version 1.6: Reset single spacing in headers/footers for use with
|
|
||||||
% setspace.sty or doublespace.sty
|
|
||||||
% Oct 4, 1994:
|
|
||||||
% version 1.7: changed \let\@mkboth\markboth to
|
|
||||||
% \def\@mkboth{\protect\markboth} to make it more robust
|
|
||||||
% Dec 5, 1994:
|
|
||||||
% version 1.8: corrections for amsbook/amsart: define \@chapapp and (more
|
|
||||||
% importantly) use the \chapter/sectionmark definitions from ps@headings if
|
|
||||||
% they exist (which should be true for all standard classes).
|
|
||||||
% May 31, 1995:
|
|
||||||
% version 1.9: The proposed \renewcommand{\headrulewidth}{\iffloatpage...
|
|
||||||
% construction in the doc did not work properly with the fancyplain style.
|
|
||||||
% June 1, 1995:
|
|
||||||
% version 1.91: The definition of \@mkboth wasn't restored on subsequent
|
|
||||||
% \pagestyle{fancy}'s.
|
|
||||||
% June 1, 1995:
|
|
||||||
% version 1.92: The sequence \pagestyle{fancyplain} \pagestyle{plain}
|
|
||||||
% \pagestyle{fancy} would erroneously select the plain version.
|
|
||||||
% June 1, 1995:
|
|
||||||
% version 1.93: \fancypagestyle command added.
|
|
||||||
% Dec 11, 1995:
|
|
||||||
% version 1.94: suggested by Conrad Hughes <chughes@maths.tcd.ie>
|
|
||||||
% CJCH, Dec 11, 1995: added \footruleskip to allow control over footrule
|
|
||||||
% position (old hardcoded value of .3\normalbaselineskip is far too high
|
|
||||||
% when used with very small footer fonts).
|
|
||||||
% Jan 31, 1996:
|
|
||||||
% version 1.95: call \@normalsize in the reset code if that is defined,
|
|
||||||
% otherwise \normalsize.
|
|
||||||
% this is to solve a problem with ucthesis.cls, as this doesn't
|
|
||||||
% define \@currsize. Unfortunately for latex209 calling \normalsize doesn't
|
|
||||||
% work as this is optimized to do very little, so there \@normalsize should
|
|
||||||
% be called. Hopefully this code works for all versions of LaTeX known to
|
|
||||||
% mankind.
|
|
||||||
% April 25, 1996:
|
|
||||||
% version 1.96: initialize \headwidth to a magic (negative) value to catch
|
|
||||||
% most common cases that people change it before calling \pagestyle{fancy}.
|
|
||||||
% Note it can't be initialized when reading in this file, because
|
|
||||||
% \textwidth could be changed afterwards. This is quite probable.
|
|
||||||
% We also switch to \MakeUppercase rather than \uppercase and introduce a
|
|
||||||
% \nouppercase command for use in headers. and footers.
|
|
||||||
% May 3, 1996:
|
|
||||||
% version 1.97: Two changes:
|
|
||||||
% 1. Undo the change in version 1.8 (using the pagestyle{headings} defaults
|
|
||||||
% for the chapter and section marks. The current version of amsbook and
|
|
||||||
% amsart classes don't seem to need them anymore. Moreover the standard
|
|
||||||
% latex classes don't use \markboth if twoside isn't selected, and this is
|
|
||||||
% confusing as \leftmark doesn't work as expected.
|
|
||||||
% 2. include a call to \ps@empty in ps@@fancy. This is to solve a problem
|
|
||||||
% in the amsbook and amsart classes, that make global changes to \topskip,
|
|
||||||
% which are reset in \ps@empty. Hopefully this doesn't break other things.
|
|
||||||
% May 7, 1996:
|
|
||||||
% version 1.98:
|
|
||||||
% Added % after the line \def\nouppercase
|
|
||||||
% May 7, 1996:
|
|
||||||
% version 1.99: This is the alpha version of fancyhdr 2.0
|
|
||||||
% Introduced the new commands \fancyhead, \fancyfoot, and \fancyhf.
|
|
||||||
% Changed \headrulewidth, \footrulewidth, \footruleskip to
|
|
||||||
% macros rather than length parameters, In this way they can be
|
|
||||||
% conditionalized and they don't consume length registers. There is no need
|
|
||||||
% to have them as length registers unless you want to do calculations with
|
|
||||||
% them, which is unlikely. Note that this may make some uses of them
|
|
||||||
% incompatible (i.e. if you have a file that uses \setlength or \xxxx=)
|
|
||||||
% May 10, 1996:
|
|
||||||
% version 1.99a:
|
|
||||||
% Added a few more % signs
|
|
||||||
% May 10, 1996:
|
|
||||||
% version 1.99b:
|
|
||||||
% Changed the syntax of \f@nfor to be resistent to catcode changes of :=
|
|
||||||
% Removed the [1] from the defs of \lhead etc. because the parameter is
|
|
||||||
% consumed by the \@[xy]lhead etc. macros.
|
|
||||||
% June 24, 1997:
|
|
||||||
% version 1.99c:
|
|
||||||
% corrected \nouppercase to also include the protected form of \MakeUppercase
|
|
||||||
% \global added to manipulation of \headwidth.
|
|
||||||
% \iffootnote command added.
|
|
||||||
% Some comments added about \@fancyhead and \@fancyfoot.
|
|
||||||
% Aug 24, 1998
|
|
||||||
% version 1.99d
|
|
||||||
% Changed the default \ps@empty to \ps@@empty in order to allow
|
|
||||||
% \fancypagestyle{empty} redefinition.
|
|
||||||
|
|
||||||
\let\fancy@def\gdef
|
|
||||||
|
|
||||||
\def\if@mpty#1#2#3{\def\temp@ty{#1}\ifx\@empty\temp@ty #2\else#3\fi}
|
|
||||||
|
|
||||||
% Usage: \@forc \var{charstring}{command to be executed for each char}
|
|
||||||
% This is similar to LaTeX's \@tfor, but expands the charstring.
|
|
||||||
|
|
||||||
\def\@forc#1#2#3{\expandafter\f@rc\expandafter#1\expandafter{#2}{#3}}
|
|
||||||
\def\f@rc#1#2#3{\def\temp@ty{#2}\ifx\@empty\temp@ty\else
|
|
||||||
\f@@rc#1#2\f@@rc{#3}\fi}
|
|
||||||
\def\f@@rc#1#2#3\f@@rc#4{\def#1{#2}#4\f@rc#1{#3}{#4}}
|
|
||||||
|
|
||||||
% Usage: \f@nfor\name:=list\do{body}
|
|
||||||
% Like LaTeX's \@for but an empty list is treated as a list with an empty
|
|
||||||
% element
|
|
||||||
|
|
||||||
\newcommand{\f@nfor}[3]{\edef\@fortmp{#2}%
|
|
||||||
\expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}}
|
|
||||||
|
|
||||||
% Usage: \def@ult \cs{defaults}{argument}
|
|
||||||
% sets \cs to the characters from defaults appearing in argument
|
|
||||||
% or defaults if it would be empty. All characters are lowercased.
|
|
||||||
|
|
||||||
\newcommand\def@ult[3]{%
|
|
||||||
\edef\temp@a{\lowercase{\edef\noexpand\temp@a{#3}}}\temp@a
|
|
||||||
\def#1{}%
|
|
||||||
\@forc\tmpf@ra{#2}%
|
|
||||||
{\expandafter\if@in\tmpf@ra\temp@a{\edef#1{#1\tmpf@ra}}{}}%
|
|
||||||
\ifx\@empty#1\def#1{#2}\fi}
|
|
||||||
%
|
|
||||||
% \if@in <char><set><truecase><falsecase>
|
|
||||||
%
|
|
||||||
\newcommand{\if@in}[4]{%
|
|
||||||
\edef\temp@a{#2}\def\temp@b##1#1##2\temp@b{\def\temp@b{##1}}%
|
|
||||||
\expandafter\temp@b#2#1\temp@b\ifx\temp@a\temp@b #4\else #3\fi}
|
|
||||||
|
|
||||||
\newcommand{\fancyhead}{\@ifnextchar[{\f@ncyhf h}{\f@ncyhf h[]}}
|
|
||||||
\newcommand{\fancyfoot}{\@ifnextchar[{\f@ncyhf f}{\f@ncyhf f[]}}
|
|
||||||
\newcommand{\fancyhf}{\@ifnextchar[{\f@ncyhf {}}{\f@ncyhf {}[]}}
|
|
||||||
|
|
||||||
% The header and footer fields are stored in command sequences with
|
|
||||||
% names of the form: \f@ncy<x><y><z> with <x> for [eo], <y> form [lcr]
|
|
||||||
% and <z> from [hf].
|
|
||||||
|
|
||||||
\def\f@ncyhf#1[#2]#3{%
|
|
||||||
\def\temp@c{}%
|
|
||||||
\@forc\tmpf@ra{#2}%
|
|
||||||
{\expandafter\if@in\tmpf@ra{eolcrhf,EOLCRHF}%
|
|
||||||
{}{\edef\temp@c{\temp@c\tmpf@ra}}}%
|
|
||||||
\ifx\@empty\temp@c\else
|
|
||||||
\ifx\PackageError\undefined
|
|
||||||
\errmessage{Illegal char `\temp@c' in fancyhdr argument:
|
|
||||||
[#2]}\else
|
|
||||||
\PackageError{Fancyhdr}{Illegal char `\temp@c' in fancyhdr argument:
|
|
||||||
[#2]}{}\fi
|
|
||||||
\fi
|
|
||||||
\f@nfor\temp@c{#2}%
|
|
||||||
{\def@ult\f@@@eo{eo}\temp@c
|
|
||||||
\def@ult\f@@@lcr{lcr}\temp@c
|
|
||||||
\def@ult\f@@@hf{hf}{#1\temp@c}%
|
|
||||||
\@forc\f@@eo\f@@@eo
|
|
||||||
{\@forc\f@@lcr\f@@@lcr
|
|
||||||
{\@forc\f@@hf\f@@@hf
|
|
||||||
{\expandafter\fancy@def\csname
|
|
||||||
f@ncy\f@@eo\f@@lcr\f@@hf\endcsname
|
|
||||||
{#3}}}}}}
|
|
||||||
|
|
||||||
% Fancyheadings version 1 commands. These are more or less deprecated,
|
|
||||||
% but they continue to work.
|
|
||||||
|
|
||||||
\newcommand{\lhead}{\@ifnextchar[{\@xlhead}{\@ylhead}}
|
|
||||||
\def\@xlhead[#1]#2{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#2}}
|
|
||||||
\def\@ylhead#1{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#1}}
|
|
||||||
|
|
||||||
\newcommand{\chead}{\@ifnextchar[{\@xchead}{\@ychead}}
|
|
||||||
\def\@xchead[#1]#2{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#2}}
|
|
||||||
\def\@ychead#1{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#1}}
|
|
||||||
|
|
||||||
\newcommand{\rhead}{\@ifnextchar[{\@xrhead}{\@yrhead}}
|
|
||||||
\def\@xrhead[#1]#2{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#2}}
|
|
||||||
\def\@yrhead#1{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#1}}
|
|
||||||
|
|
||||||
\newcommand{\lfoot}{\@ifnextchar[{\@xlfoot}{\@ylfoot}}
|
|
||||||
\def\@xlfoot[#1]#2{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#2}}
|
|
||||||
\def\@ylfoot#1{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#1}}
|
|
||||||
|
|
||||||
\newcommand{\cfoot}{\@ifnextchar[{\@xcfoot}{\@ycfoot}}
|
|
||||||
\def\@xcfoot[#1]#2{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#2}}
|
|
||||||
\def\@ycfoot#1{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#1}}
|
|
||||||
|
|
||||||
\newcommand{\rfoot}{\@ifnextchar[{\@xrfoot}{\@yrfoot}}
|
|
||||||
\def\@xrfoot[#1]#2{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#2}}
|
|
||||||
\def\@yrfoot#1{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#1}}
|
|
||||||
|
|
||||||
\newdimen\headwidth
|
|
||||||
\newcommand{\headrulewidth}{0.4pt}
|
|
||||||
\newcommand{\footrulewidth}{\z@skip}
|
|
||||||
\newcommand{\footruleskip}{.3\normalbaselineskip}
|
|
||||||
|
|
||||||
% Fancyplain stuff shouldn't be used anymore (rather
|
|
||||||
% \fancypagestyle{plain} should be used), but it must be present for
|
|
||||||
% compatibility reasons.
|
|
||||||
|
|
||||||
\newcommand{\plainheadrulewidth}{\z@skip}
|
|
||||||
\newcommand{\plainfootrulewidth}{\z@skip}
|
|
||||||
\newif\if@fancyplain \@fancyplainfalse
|
|
||||||
\def\fancyplain#1#2{\if@fancyplain#1\else#2\fi}
|
|
||||||
|
|
||||||
\headwidth=-123456789sp %magic constant
|
|
||||||
|
|
||||||
% Command to reset various things in the headers:
|
|
||||||
% a.o. single spacing (taken from setspace.sty)
|
|
||||||
% and the catcode of ^^M (so that epsf files in the header work if a
|
|
||||||
% verbatim crosses a page boundary)
|
|
||||||
% It also defines a \nouppercase command that disables \uppercase and
|
|
||||||
% \Makeuppercase. It can only be used in the headers and footers.
|
|
||||||
\def\fancy@reset{\restorecr
|
|
||||||
\def\baselinestretch{1}%
|
|
||||||
\def\nouppercase##1{{\let\uppercase\relax\let\MakeUppercase\relax
|
|
||||||
\expandafter\let\csname MakeUppercase \endcsname\relax##1}}%
|
|
||||||
\ifx\undefined\@newbaseline% NFSS not present; 2.09 or 2e
|
|
||||||
\ifx\@normalsize\undefined \normalsize % for ucthesis.cls
|
|
||||||
\else \@normalsize \fi
|
|
||||||
\else% NFSS (2.09) present
|
|
||||||
\@newbaseline%
|
|
||||||
\fi}
|
|
||||||
|
|
||||||
% Initialization of the head and foot text.
|
|
||||||
|
|
||||||
% The default values still contain \fancyplain for compatibility.
|
|
||||||
\fancyhf{} % clear all
|
|
||||||
% lefthead empty on ``plain'' pages, \rightmark on even, \leftmark on odd pages
|
|
||||||
% evenhead empty on ``plain'' pages, \leftmark on even, \rightmark on odd pages
|
|
||||||
\fancyhead[el,or]{\fancyplain{}{\sl\rightmark}}
|
|
||||||
\fancyhead[er,ol]{\fancyplain{}{\sl\leftmark}}
|
|
||||||
\fancyfoot[c]{\rm\thepage} % page number
|
|
||||||
|
|
||||||
% Put together a header or footer given the left, center and
|
|
||||||
% right text, fillers at left and right and a rule.
|
|
||||||
% The \lap commands put the text into an hbox of zero size,
|
|
||||||
% so overlapping text does not generate an errormessage.
|
|
||||||
% These macros have 5 parameters:
|
|
||||||
% 1. \@lodd or \@rodd % This determines at which side the header will stick
|
|
||||||
% out.
|
|
||||||
% 2. \f@ncyolh, \f@ncyelh, \f@ncyolf or \f@ncyelf. This is the left component.
|
|
||||||
% 3. \f@ncyoch, \f@ncyech, \f@ncyocf or \f@ncyecf. This is the middle comp.
|
|
||||||
% 4. \f@ncyorh, \f@ncyerh, \f@ncyorf or \f@ncyerf. This is the right component.
|
|
||||||
% 5. \@lodd or \@rodd % This determines at which side the header will stick
|
|
||||||
% out. This is the reverse of parameter nr. 1. One of them is always
|
|
||||||
% \relax and the other one is \hss (after expansion).
|
|
||||||
|
|
||||||
\def\@fancyhead#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\hbox
|
|
||||||
{\rlap{\parbox[b]{\headwidth}{\raggedright#2\strut}}\hfill
|
|
||||||
\parbox[b]{\headwidth}{\centering#3\strut}\hfill
|
|
||||||
\llap{\parbox[b]{\headwidth}{\raggedleft#4\strut}}}\headrule}}#5}
|
|
||||||
|
|
||||||
\def\@fancyfoot#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\footrule
|
|
||||||
\hbox{\rlap{\parbox[t]{\headwidth}{\raggedright#2\strut}}\hfill
|
|
||||||
\parbox[t]{\headwidth}{\centering#3\strut}\hfill
|
|
||||||
\llap{\parbox[t]{\headwidth}{\raggedleft#4\strut}}}}}#5}
|
|
||||||
|
|
||||||
\def\headrule{{\if@fancyplain\let\headrulewidth\plainheadrulewidth\fi
|
|
||||||
\hrule\@height\headrulewidth\@width\headwidth \vskip-\headrulewidth}}
|
|
||||||
|
|
||||||
\def\footrule{{\if@fancyplain\let\footrulewidth\plainfootrulewidth\fi
|
|
||||||
\vskip-\footruleskip\vskip-\footrulewidth
|
|
||||||
\hrule\@width\headwidth\@height\footrulewidth\vskip\footruleskip}}
|
|
||||||
|
|
||||||
\def\ps@fancy{%
|
|
||||||
\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}%for amsbook
|
|
||||||
%
|
|
||||||
% Define \MakeUppercase for old LaTeXen.
|
|
||||||
% Note: we used \def rather than \let, so that \let\uppercase\relax (from
|
|
||||||
% the version 1 documentation) will still work.
|
|
||||||
%
|
|
||||||
\@ifundefined{MakeUppercase}{\def\MakeUppercase{\uppercase}}{}%
|
|
||||||
\@ifundefined{chapter}{\def\sectionmark##1{\markboth
|
|
||||||
{\MakeUppercase{\ifnum \c@secnumdepth>\z@
|
|
||||||
\thesection\hskip 1em\relax \fi ##1}}{}}%
|
|
||||||
\def\subsectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne
|
|
||||||
\thesubsection\hskip 1em\relax \fi ##1}}}%
|
|
||||||
{\def\chaptermark##1{\markboth {\MakeUppercase{\ifnum \c@secnumdepth>\m@ne
|
|
||||||
\@chapapp\ \thechapter. \ \fi ##1}}{}}%
|
|
||||||
\def\sectionmark##1{\markright{\MakeUppercase{\ifnum \c@secnumdepth >\z@
|
|
||||||
\thesection. \ \fi ##1}}}}%
|
|
||||||
%\csname ps@headings\endcsname % use \ps@headings defaults if they exist
|
|
||||||
\ps@@fancy
|
|
||||||
\gdef\ps@fancy{\@fancyplainfalse\ps@@fancy}%
|
|
||||||
% Initialize \headwidth if the user didn't
|
|
||||||
%
|
|
||||||
\ifdim\headwidth<0sp
|
|
||||||
%
|
|
||||||
% This catches the case that \headwidth hasn't been initialized and the
|
|
||||||
% case that the user added something to \headwidth in the expectation that
|
|
||||||
% it was initialized to \textwidth. We compensate this now. This loses if
|
|
||||||
% the user intended to multiply it by a factor. But that case is more
|
|
||||||
% likely done by saying something like \headwidth=1.2\textwidth.
|
|
||||||
% The doc says you have to change \headwidth after the first call to
|
|
||||||
% \pagestyle{fancy}. This code is just to catch the most common cases were
|
|
||||||
% that requirement is violated.
|
|
||||||
%
|
|
||||||
\global\advance\headwidth123456789sp\global\advance\headwidth\textwidth
|
|
||||||
\fi}
|
|
||||||
\def\ps@fancyplain{\ps@fancy \let\ps@plain\ps@plain@fancy}
|
|
||||||
\def\ps@plain@fancy{\@fancyplaintrue\ps@@fancy}
|
|
||||||
\let\ps@@empty\ps@empty
|
|
||||||
\def\ps@@fancy{%
|
|
||||||
\ps@@empty % This is for amsbook/amsart, which do strange things with \topskip
|
|
||||||
\def\@mkboth{\protect\markboth}%
|
|
||||||
\def\@oddhead{\@fancyhead\@lodd\f@ncyolh\f@ncyoch\f@ncyorh\@rodd}%
|
|
||||||
\def\@oddfoot{\@fancyfoot\@lodd\f@ncyolf\f@ncyocf\f@ncyorf\@rodd}%
|
|
||||||
\def\@evenhead{\@fancyhead\@rodd\f@ncyelh\f@ncyech\f@ncyerh\@lodd}%
|
|
||||||
\def\@evenfoot{\@fancyfoot\@rodd\f@ncyelf\f@ncyecf\f@ncyerf\@lodd}%
|
|
||||||
}
|
|
||||||
\def\@lodd{\if@reversemargin\hss\else\relax\fi}
|
|
||||||
\def\@rodd{\if@reversemargin\relax\else\hss\fi}
|
|
||||||
|
|
||||||
\newif\iffootnote
|
|
||||||
\let\latex@makecol\@makecol
|
|
||||||
\def\@makecol{\ifvoid\footins\footnotetrue\else\footnotefalse\fi
|
|
||||||
\let\topfloat\@toplist\let\botfloat\@botlist\latex@makecol}
|
|
||||||
\def\iftopfloat#1#2{\ifx\topfloat\empty #2\else #1\fi}
|
|
||||||
\def\ifbotfloat#1#2{\ifx\botfloat\empty #2\else #1\fi}
|
|
||||||
\def\iffloatpage#1#2{\if@fcolmade #1\else #2\fi}
|
|
||||||
|
|
||||||
\newcommand{\fancypagestyle}[2]{%
|
|
||||||
\@namedef{ps@#1}{\let\fancy@def\def#2\relax\ps@fancy}}
|
|
@ -1,433 +0,0 @@
|
|||||||
%%% Derived from the original fncychap.sty,
|
|
||||||
%%% but changed ``TWELV'' to ``TWELVE''.
|
|
||||||
|
|
||||||
%%% Copyright Ulf A. Lindgren
|
|
||||||
%%% Department of Applied Electronics
|
|
||||||
%%% Chalmers University of Technology
|
|
||||||
%%% S-412 96 Gothenburg, Sweden
|
|
||||||
%%% E-mail lindgren@ae.chalmers.se
|
|
||||||
%%%
|
|
||||||
%%% Note Permission is granted to modify this file under
|
|
||||||
%%% the condition that it is saved using another
|
|
||||||
%%% file and package name.
|
|
||||||
%%%
|
|
||||||
%%% Revision 1.1
|
|
||||||
%%%
|
|
||||||
%%% Jan. 8th Modified package name base date option
|
|
||||||
%%% Jan. 22th Modified FmN and FmTi for error in book.cls
|
|
||||||
%%% \MakeUppercase{#}->{\MakeUppercase#}
|
|
||||||
%%% Apr. 6th Modified Lenny option to prevent undesired
|
|
||||||
%%% skip of line.
|
|
||||||
%%% Nov. 8th Fixed \@chapapp for AMS
|
|
||||||
%%% Feb. 11th Fixed appendix problem related to Bjarne
|
|
||||||
%%% Last modified Feb. 11th 1998
|
|
||||||
|
|
||||||
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
|
|
||||||
\ProvidesPackage{fncychap}
|
|
||||||
[1997/04/06 v1.11
|
|
||||||
LaTeX package (Revised chapters)]
|
|
||||||
|
|
||||||
%%%% DEFINITION OF Chapapp variables
|
|
||||||
\newcommand{\CNV}{\huge\bfseries}
|
|
||||||
\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}}
|
|
||||||
|
|
||||||
|
|
||||||
%%%% DEFINITION OF TheChapter variables
|
|
||||||
\newcommand{\CNoV}{\huge\bfseries}
|
|
||||||
\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}}
|
|
||||||
|
|
||||||
\newif\ifUCN
|
|
||||||
\UCNfalse
|
|
||||||
\newif\ifLCN
|
|
||||||
\LCNfalse
|
|
||||||
\def\ChNameLowerCase{\LCNtrue\UCNfalse}
|
|
||||||
\def\ChNameUpperCase{\UCNtrue\LCNfalse}
|
|
||||||
\def\ChNameAsIs{\UCNfalse\LCNfalse}
|
|
||||||
|
|
||||||
%%%%% Fix for AMSBook 971008
|
|
||||||
|
|
||||||
\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}
|
|
||||||
|
|
||||||
|
|
||||||
%%%%% Fix for Bjarne and appendix 980211
|
|
||||||
|
|
||||||
\newif\ifinapp
|
|
||||||
\inappfalse
|
|
||||||
\renewcommand\appendix{\par
|
|
||||||
\setcounter{chapter}{0}%
|
|
||||||
\setcounter{section}{0}%
|
|
||||||
\inapptrue%
|
|
||||||
\renewcommand\@chapapp{\appendixname}%
|
|
||||||
\renewcommand\thechapter{\@Alph\c@chapter}}
|
|
||||||
|
|
||||||
%%%%%
|
|
||||||
|
|
||||||
\newcommand{\FmN}[1]{%
|
|
||||||
\ifUCN
|
|
||||||
{\MakeUppercase#1}\LCNfalse
|
|
||||||
\else
|
|
||||||
\ifLCN
|
|
||||||
{\MakeLowercase#1}\UCNfalse
|
|
||||||
\else #1
|
|
||||||
\fi
|
|
||||||
\fi}
|
|
||||||
|
|
||||||
|
|
||||||
%%%% DEFINITION OF Title variables
|
|
||||||
\newcommand{\CTV}{\Huge\bfseries}
|
|
||||||
\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}}
|
|
||||||
|
|
||||||
%%%% DEFINITION OF the basic rule width
|
|
||||||
\newlength{\RW}
|
|
||||||
\setlength{\RW}{1pt}
|
|
||||||
\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}}
|
|
||||||
|
|
||||||
\newif\ifUCT
|
|
||||||
\UCTfalse
|
|
||||||
\newif\ifLCT
|
|
||||||
\LCTfalse
|
|
||||||
\def\ChTitleLowerCase{\LCTtrue\UCTfalse}
|
|
||||||
\def\ChTitleUpperCase{\UCTtrue\LCTfalse}
|
|
||||||
\def\ChTitleAsIs{\UCTfalse\LCTfalse}
|
|
||||||
\newcommand{\FmTi}[1]{%
|
|
||||||
\ifUCT
|
|
||||||
|
|
||||||
{\MakeUppercase#1}\LCTfalse
|
|
||||||
\else
|
|
||||||
\ifLCT
|
|
||||||
{\MakeLowercase#1}\UCTfalse
|
|
||||||
\else #1
|
|
||||||
\fi
|
|
||||||
\fi}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\newlength{\mylen}
|
|
||||||
\newlength{\myhi}
|
|
||||||
\newlength{\px}
|
|
||||||
\newlength{\py}
|
|
||||||
\newlength{\pyy}
|
|
||||||
\newlength{\pxx}
|
|
||||||
|
|
||||||
|
|
||||||
\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@}
|
|
||||||
|
|
||||||
\newcommand{\DOCH}{%
|
|
||||||
\CNV\FmN{\@chapapp}\space \CNoV\thechapter
|
|
||||||
\par\nobreak
|
|
||||||
\vskip 20\p@
|
|
||||||
}
|
|
||||||
\newcommand{\DOTI}[1]{%
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@
|
|
||||||
}
|
|
||||||
\newcommand{\DOTIS}[1]{%
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@
|
|
||||||
}
|
|
||||||
|
|
||||||
%%%%%% SONNY DEF
|
|
||||||
|
|
||||||
\DeclareOption{Sonny}{%
|
|
||||||
\ChNameVar{\Large\sf}
|
|
||||||
\ChNumVar{\Huge}
|
|
||||||
\ChTitleVar{\Large\sf}
|
|
||||||
\ChRuleWidth{0.5pt}
|
|
||||||
\ChNameUpperCase
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\raggedleft
|
|
||||||
\CNV\FmN{\@chapapp}\space \CNoV\thechapter
|
|
||||||
\par\nobreak
|
|
||||||
\vskip 40\p@}
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\CTV\raggedleft\mghrulefill{\RW}\par\nobreak
|
|
||||||
\vskip 5\p@
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\vskip 40\p@}
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\CTV\raggedleft\mghrulefill{\RW}\par\nobreak
|
|
||||||
\vskip 5\p@
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\vskip 40\p@}
|
|
||||||
}
|
|
||||||
|
|
||||||
%%%%%% LENNY DEF
|
|
||||||
|
|
||||||
\DeclareOption{Lenny}{%
|
|
||||||
|
|
||||||
\ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont}
|
|
||||||
\ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont}
|
|
||||||
\ChTitleVar{\Huge\bfseries\rm}
|
|
||||||
\ChRuleWidth{1pt}
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\settowidth{\px}{\CNV\FmN{\@chapapp}}
|
|
||||||
\addtolength{\px}{2pt}
|
|
||||||
\settoheight{\py}{\CNV\FmN{\@chapapp}}
|
|
||||||
\addtolength{\py}{1pt}
|
|
||||||
|
|
||||||
\settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter}
|
|
||||||
\addtolength{\mylen}{1pt}
|
|
||||||
\settowidth{\pxx}{\CNoV\thechapter}
|
|
||||||
\addtolength{\pxx}{-1pt}
|
|
||||||
|
|
||||||
\settoheight{\pyy}{\CNoV\thechapter}
|
|
||||||
\addtolength{\pyy}{-2pt}
|
|
||||||
\setlength{\myhi}{\pyy}
|
|
||||||
\addtolength{\myhi}{-1\py}
|
|
||||||
\par
|
|
||||||
\parbox[b]{\textwidth}{%
|
|
||||||
\rule[\py]{\RW}{\myhi}%
|
|
||||||
\hskip -\RW%
|
|
||||||
\rule[\pyy]{\px}{\RW}%
|
|
||||||
\hskip -\px%
|
|
||||||
\raggedright%
|
|
||||||
\CNV\FmN{\@chapapp}\space\CNoV\thechapter%
|
|
||||||
\hskip1pt%
|
|
||||||
\mghrulefill{\RW}%
|
|
||||||
\rule{\RW}{\pyy}\par\nobreak%
|
|
||||||
\vskip -\baselineskip%
|
|
||||||
\vskip -\pyy%
|
|
||||||
\hskip \mylen%
|
|
||||||
\mghrulefill{\RW}\par\nobreak%
|
|
||||||
\vskip \pyy}%
|
|
||||||
\vskip 20\p@}
|
|
||||||
|
|
||||||
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\raggedright
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@}
|
|
||||||
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\raggedright
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%% GLENN DEF
|
|
||||||
|
|
||||||
|
|
||||||
\DeclareOption{Glenn}{%
|
|
||||||
\ChNameVar{\bfseries\Large\sf}
|
|
||||||
\ChNumVar{\Huge}
|
|
||||||
\ChTitleVar{\bfseries\Large\rm}
|
|
||||||
\ChRuleWidth{1pt}
|
|
||||||
\ChNameUpperCase
|
|
||||||
\ChTitleUpperCase
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\settoheight{\myhi}{\CTV\FmTi{Test}}
|
|
||||||
\setlength{\py}{\baselineskip}
|
|
||||||
\addtolength{\py}{\RW}
|
|
||||||
\addtolength{\py}{\myhi}
|
|
||||||
\setlength{\pyy}{\py}
|
|
||||||
\addtolength{\pyy}{-1\RW}
|
|
||||||
|
|
||||||
\raggedright
|
|
||||||
\CNV\FmN{\@chapapp}\space\CNoV\thechapter
|
|
||||||
\hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak}
|
|
||||||
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\addtolength{\pyy}{-4pt}
|
|
||||||
\settoheight{\myhi}{\CTV\FmTi{#1}}
|
|
||||||
\addtolength{\myhi}{\py}
|
|
||||||
\addtolength{\myhi}{-1\RW}
|
|
||||||
\vskip -1\pyy
|
|
||||||
\rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
|
|
||||||
\raggedleft\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 80\p@}
|
|
||||||
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\setlength{\py}{10pt}
|
|
||||||
\setlength{\pyy}{\py}
|
|
||||||
\addtolength{\pyy}{\RW}
|
|
||||||
\setlength{\myhi}{\baselineskip}
|
|
||||||
\addtolength{\myhi}{\pyy}
|
|
||||||
\mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak
|
|
||||||
% \addtolength{}{}
|
|
||||||
\vskip -1\baselineskip
|
|
||||||
\rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt
|
|
||||||
\raggedleft\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 60\p@}
|
|
||||||
}
|
|
||||||
|
|
||||||
%%%%%%% CONNY DEF
|
|
||||||
|
|
||||||
\DeclareOption{Conny}{%
|
|
||||||
\ChNameUpperCase
|
|
||||||
\ChTitleUpperCase
|
|
||||||
\ChNameVar{\centering\Huge\rm\bfseries}
|
|
||||||
\ChNumVar{\Huge}
|
|
||||||
\ChTitleVar{\centering\Huge\rm}
|
|
||||||
\ChRuleWidth{2pt}
|
|
||||||
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\mghrulefill{3\RW}\par\nobreak
|
|
||||||
\vskip -0.5\baselineskip
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\CNV\FmN{\@chapapp}\space \CNoV\thechapter
|
|
||||||
\par\nobreak
|
|
||||||
\vskip -0.5\baselineskip
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 60\p@
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 60\p@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%%%%%%% REJNE DEF
|
|
||||||
|
|
||||||
\DeclareOption{Rejne}{%
|
|
||||||
|
|
||||||
\ChNameUpperCase
|
|
||||||
\ChTitleUpperCase
|
|
||||||
\ChNameVar{\centering\Large\rm}
|
|
||||||
\ChNumVar{\Huge}
|
|
||||||
\ChTitleVar{\centering\Huge\rm}
|
|
||||||
\ChRuleWidth{1pt}
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\settoheight{\py}{\CNoV\thechapter}
|
|
||||||
\addtolength{\py}{-1pt}
|
|
||||||
\CNV\FmN{\@chapapp}\par\nobreak
|
|
||||||
\vskip 20\p@
|
|
||||||
\setlength{\myhi}{2\baselineskip}
|
|
||||||
\setlength{\px}{\myhi}
|
|
||||||
\addtolength{\px}{-1\RW}
|
|
||||||
\rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip
|
|
||||||
10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip
|
|
||||||
10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak
|
|
||||||
\vskip -1\p@
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\setlength{\mylen}{\textwidth}
|
|
||||||
\addtolength{\mylen}{-2\RW}
|
|
||||||
{\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule
|
|
||||||
width\RW}\par\nobreak
|
|
||||||
\vskip
|
|
||||||
-1pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip}
|
|
||||||
\vskip 60\p@
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\setlength{\py}{\fboxrule}
|
|
||||||
\setlength{\fboxrule}{\RW}
|
|
||||||
\setlength{\mylen}{\textwidth}
|
|
||||||
\addtolength{\mylen}{-2\RW}
|
|
||||||
\fbox{\parbox{\mylen}{\vskip
|
|
||||||
2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}}
|
|
||||||
\setlength{\fboxrule}{\py}
|
|
||||||
\vskip 60\p@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%% BJARNE DEF
|
|
||||||
|
|
||||||
\DeclareOption{Bjarne}{%
|
|
||||||
\ChNameUpperCase
|
|
||||||
\ChTitleUpperCase
|
|
||||||
\ChNameVar{\raggedleft\normalsize\rm}
|
|
||||||
\ChNumVar{\raggedleft \bfseries\Large}
|
|
||||||
\ChTitleVar{\raggedleft \Large\rm}
|
|
||||||
\ChRuleWidth{1pt}
|
|
||||||
|
|
||||||
|
|
||||||
%% Note thechapter -> c@chapter fix appendix bug
|
|
||||||
|
|
||||||
\newcounter{AlphaCnt}
|
|
||||||
\newcounter{AlphaDecCnt}
|
|
||||||
\newcommand{\AlphaNo}{%
|
|
||||||
\ifcase\number\theAlphaCnt
|
|
||||||
\ifnum\c@chapter=0
|
|
||||||
ZERO\else{}\fi
|
|
||||||
\or ONE\or TWO\or THREE\or FOUR\or FIVE
|
|
||||||
\or SIX\or SEVEN\or EIGHT\or NINE\or TEN
|
|
||||||
\or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN
|
|
||||||
\or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi
|
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\AlphaDecNo}{%
|
|
||||||
\setcounter{AlphaDecCnt}{0}
|
|
||||||
\@whilenum\number\theAlphaCnt>0\do
|
|
||||||
{\addtocounter{AlphaCnt}{-10}
|
|
||||||
\addtocounter{AlphaDecCnt}{1}}
|
|
||||||
\ifnum\number\theAlphaCnt=0
|
|
||||||
\else
|
|
||||||
\addtocounter{AlphaDecCnt}{-1}
|
|
||||||
\addtocounter{AlphaCnt}{10}
|
|
||||||
\fi
|
|
||||||
|
|
||||||
|
|
||||||
\ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or
|
|
||||||
FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi
|
|
||||||
}
|
|
||||||
\newcommand{\TheAlphaChapter}{%
|
|
||||||
|
|
||||||
\ifinapp
|
|
||||||
\thechapter
|
|
||||||
\else
|
|
||||||
\setcounter{AlphaCnt}{\c@chapter}
|
|
||||||
\ifnum\c@chapter<20
|
|
||||||
\AlphaNo
|
|
||||||
\else
|
|
||||||
\AlphaDecNo\AlphaNo
|
|
||||||
\fi
|
|
||||||
\fi
|
|
||||||
}
|
|
||||||
\renewcommand{\DOCH}{%
|
|
||||||
\mghrulefill{\RW}\par\nobreak
|
|
||||||
\CNV\FmN{\@chapapp}\par\nobreak
|
|
||||||
\CNoV\TheAlphaChapter\par\nobreak
|
|
||||||
\vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak
|
|
||||||
\vskip 20\p@
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTI}[1]{%
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@
|
|
||||||
}
|
|
||||||
\renewcommand{\DOTIS}[1]{%
|
|
||||||
\CTV\FmTi{#1}\par\nobreak
|
|
||||||
\vskip 40\p@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
\DeclareOption*{%
|
|
||||||
\PackageWarning{fancychapter}{unknown style option}
|
|
||||||
}
|
|
||||||
|
|
||||||
\ProcessOptions* \relax
|
|
||||||
|
|
||||||
\def\@makechapterhead#1{%
|
|
||||||
\vspace*{50\p@}%
|
|
||||||
{\parindent \z@ \raggedright \normalfont
|
|
||||||
\ifnum \c@secnumdepth >\m@ne
|
|
||||||
\DOCH
|
|
||||||
\fi
|
|
||||||
\interlinepenalty\@M
|
|
||||||
\DOTI{#1}
|
|
||||||
}}
|
|
||||||
\def\@schapter#1{\if@twocolumn
|
|
||||||
\@topnewpage[\@makeschapterhead{#1}]%
|
|
||||||
\else
|
|
||||||
\@makeschapterhead{#1}%
|
|
||||||
\@afterheading
|
|
||||||
\fi}
|
|
||||||
\def\@makeschapterhead#1{%
|
|
||||||
\vspace*{50\p@}%
|
|
||||||
{\parindent \z@ \raggedright
|
|
||||||
\normalfont
|
|
||||||
\interlinepenalty\@M
|
|
||||||
\DOTIS{#1}
|
|
||||||
\vskip 40\p@
|
|
||||||
}}
|
|
||||||
|
|
||||||
\endinput
|
|
||||||
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
|||||||
%
|
|
||||||
% howto.cls for the Python documentation
|
|
||||||
%
|
|
||||||
|
|
||||||
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
|
|
||||||
\ProvidesClass{howto}
|
|
||||||
[1998/02/25 Document class (Python HOWTO)]
|
|
||||||
|
|
||||||
\RequirePackage{pypaper}
|
|
||||||
|
|
||||||
% Change the options here to get a different set of basic options, This
|
|
||||||
% is where to add things like "a4paper" or "10pt".
|
|
||||||
%
|
|
||||||
\LoadClass[\py@paper,\py@ptsize,twoside]{article}
|
|
||||||
|
|
||||||
\setcounter{secnumdepth}{1}
|
|
||||||
|
|
||||||
% Optional packages:
|
|
||||||
%
|
|
||||||
% If processing of these documents fails at your TeX installation,
|
|
||||||
% these may be commented out (independently) to make things work.
|
|
||||||
% These are both supplied with the current version of the teTeX
|
|
||||||
% distribution.
|
|
||||||
%
|
|
||||||
% The "fancyhdr" package makes nicer page footers reasonable to
|
|
||||||
% implement, and is used to put the chapter and section information in
|
|
||||||
% the footers.
|
|
||||||
%
|
|
||||||
\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.}
|
|
||||||
|
|
||||||
|
|
||||||
% Required package:
|
|
||||||
%
|
|
||||||
% This gives us all the Python-specific markup that we really want.
|
|
||||||
% This should come last. Do not change this.
|
|
||||||
%
|
|
||||||
\RequirePackage{python}
|
|
||||||
|
|
||||||
% support for module synopsis sections:
|
|
||||||
\newcommand{\py@ModSynopsisFilename}{\jobname.syn}
|
|
||||||
|
|
||||||
|
|
||||||
% need to do one of these....
|
|
||||||
\newcommand{\py@doHorizontalRule}{\rule{\textwidth}{1pt}}
|
|
||||||
|
|
||||||
|
|
||||||
% Change the title page to look a bit better, and fit in with the
|
|
||||||
% fncychap ``Bjarne'' style a bit better.
|
|
||||||
%
|
|
||||||
\renewcommand{\maketitle}{
|
|
||||||
\py@doHorizontalRule
|
|
||||||
\@ifundefined{pdfinfo}{}{{
|
|
||||||
% This \def is required to deal with multi-line authors; it
|
|
||||||
% changes \\ to ', ' (comma-space), making it pass muster for
|
|
||||||
% generating document info in the PDF file.
|
|
||||||
\def\\{, }
|
|
||||||
\pdfinfo{
|
|
||||||
/Author (\@author)
|
|
||||||
/Title (\@title)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
\begin{flushright}
|
|
||||||
{\rm\Huge\py@HeaderFamily \@title} \par
|
|
||||||
{\em\large\py@HeaderFamily \py@release\releaseinfo} \par
|
|
||||||
\vspace{25pt}
|
|
||||||
{\Large\py@HeaderFamily \@author} \par
|
|
||||||
\vspace{25pt}
|
|
||||||
\@date \par
|
|
||||||
\py@authoraddress \par
|
|
||||||
\end{flushright}
|
|
||||||
\@thanks
|
|
||||||
\setcounter{footnote}{0}
|
|
||||||
\let\thanks\relax\let\maketitle\relax
|
|
||||||
\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
\let\py@OldTableofcontents=\tableofcontents
|
|
||||||
\renewcommand{\tableofcontents}{
|
|
||||||
\begingroup
|
|
||||||
\parskip = 0mm
|
|
||||||
\py@OldTableofcontents
|
|
||||||
\endgroup
|
|
||||||
\py@doHorizontalRule
|
|
||||||
\vspace{12pt}
|
|
||||||
\py@doing@page@targetstrue
|
|
||||||
}
|
|
||||||
|
|
||||||
% Fix the theindex environment to add an entry to the Table of
|
|
||||||
% Contents; this is much nicer than just having to jump to the end of
|
|
||||||
% the book and flip around, especially with multiple indexes.
|
|
||||||
%
|
|
||||||
\let\py@OldTheindex=\theindex
|
|
||||||
\renewcommand{\theindex}{
|
|
||||||
\clearpage
|
|
||||||
\py@OldTheindex
|
|
||||||
\addcontentsline{toc}{section}{\indexname}
|
|
||||||
}
|
|
||||||
|
|
||||||
\@ifundefined{fancyhf}{
|
|
||||||
\pagestyle{plain}}{
|
|
||||||
\pagestyle{normal}} % start this way; change for
|
|
||||||
\pagenumbering{arabic} % ToC & chapters
|
|
||||||
\setcounter{secnumdepth}{2}
|
|
||||||
|
|
||||||
\thispagestyle{empty}
|
|
@ -1,274 +0,0 @@
|
|||||||
\section{History of the software}
|
|
||||||
|
|
||||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
|
||||||
Mathematisch Centrum (CWI, see \url{http://www.cwi.nl/}) in the Netherlands
|
|
||||||
as a successor of a language called ABC. Guido remains Python's
|
|
||||||
principal author, although it includes many contributions from others.
|
|
||||||
|
|
||||||
In 1995, Guido continued his work on Python at the Corporation for
|
|
||||||
National Research Initiatives (CNRI, see \url{http://www.cnri.reston.va.us/})
|
|
||||||
in Reston, Virginia where he released several versions of the
|
|
||||||
software.
|
|
||||||
|
|
||||||
In May 2000, Guido and the Python core development team moved to
|
|
||||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
|
||||||
year, the PythonLabs team moved to Digital Creations (now Zope
|
|
||||||
Corporation; see \url{http://www.zope.com/}). In 2001, the Python
|
|
||||||
Software Foundation (PSF, see \url{http://www.python.org/psf/}) was
|
|
||||||
formed, a non-profit organization created specifically to own
|
|
||||||
Python-related Intellectual Property. Zope Corporation is a
|
|
||||||
sponsoring member of the PSF.
|
|
||||||
|
|
||||||
All Python releases are Open Source (see
|
|
||||||
\url{http://www.opensource.org/} for the Open Source Definition).
|
|
||||||
Historically, most, but not all, Python releases have also been
|
|
||||||
GPL-compatible; the table below summarizes the various releases.
|
|
||||||
|
|
||||||
\begin{tablev}{c|c|c|c|c}{textrm}{Release}{Derived from}{Year}{Owner}{GPL compatible?}
|
|
||||||
\linev{0.9.0 thru 1.2}{n/a}{1991-1995}{CWI}{yes}
|
|
||||||
\linev{1.3 thru 1.5.2}{1.2}{1995-1999}{CNRI}{yes}
|
|
||||||
\linev{1.6}{1.5.2}{2000}{CNRI}{no}
|
|
||||||
\linev{2.0}{1.6}{2000}{BeOpen.com}{no}
|
|
||||||
\linev{1.6.1}{1.6}{2001}{CNRI}{no}
|
|
||||||
\linev{2.1}{2.0+1.6.1}{2001}{PSF}{no}
|
|
||||||
\linev{2.0.1}{2.0+1.6.1}{2001}{PSF}{yes}
|
|
||||||
\linev{2.1.1}{2.1+2.0.1}{2001}{PSF}{yes}
|
|
||||||
\linev{2.2}{2.1.1}{2001}{PSF}{yes}
|
|
||||||
\linev{2.1.2}{2.1.1}{2002}{PSF}{yes}
|
|
||||||
\linev{2.1.3}{2.1.2}{2002}{PSF}{yes}
|
|
||||||
\linev{2.2.1}{2.2}{2002}{PSF}{yes}
|
|
||||||
\end{tablev}
|
|
||||||
|
|
||||||
\note{GPL-compatible doesn't mean that we're distributing
|
|
||||||
Python under the GPL. All Python licenses, unlike the GPL, let you
|
|
||||||
distribute a modified version without making your changes open source.
|
|
||||||
The GPL-compatible licenses make it possible to combine Python with
|
|
||||||
other software that is released under the GPL; the others don't.}
|
|
||||||
|
|
||||||
Thanks to the many outside volunteers who have worked under Guido's
|
|
||||||
direction to make these releases possible.
|
|
||||||
|
|
||||||
|
|
||||||
\section{Terms and conditions for accessing or otherwise using Python}
|
|
||||||
|
|
||||||
\centerline{\strong{PSF LICENSE AGREEMENT FOR PYTHON 2.3}}
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item
|
|
||||||
This LICENSE AGREEMENT is between the Python Software Foundation
|
|
||||||
(``PSF''), and the Individual or Organization (``Licensee'') accessing
|
|
||||||
and otherwise using Python \version{} software in source or binary
|
|
||||||
form and its associated documentation.
|
|
||||||
|
|
||||||
\item
|
|
||||||
Subject to the terms and conditions of this License Agreement, PSF
|
|
||||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
|
||||||
license to reproduce, analyze, test, perform and/or display publicly,
|
|
||||||
prepare derivative works, distribute, and otherwise use Python
|
|
||||||
\version{} alone or in any derivative version, provided, however, that
|
|
||||||
PSF's License Agreement and PSF's notice of copyright, i.e.,
|
|
||||||
``Copyright \copyright{} 2001, 2002 Python Software Foundation; All
|
|
||||||
Rights Reserved'' are retained in Python \version{} alone or in any
|
|
||||||
derivative version prepared by Licensee.
|
|
||||||
|
|
||||||
\item
|
|
||||||
In the event Licensee prepares a derivative work that is based on
|
|
||||||
or incorporates Python \version{} or any part thereof, and wants to
|
|
||||||
make the derivative work available to others as provided herein, then
|
|
||||||
Licensee hereby agrees to include in any such work a brief summary of
|
|
||||||
the changes made to Python \version.
|
|
||||||
|
|
||||||
\item
|
|
||||||
PSF is making Python \version{} available to Licensee on an ``AS IS''
|
|
||||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
|
||||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
|
||||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
||||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON \version{} WILL
|
|
||||||
NOT INFRINGE ANY THIRD PARTY RIGHTS.
|
|
||||||
|
|
||||||
\item
|
|
||||||
PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
|
||||||
\version{} FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
|
|
||||||
LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON
|
|
||||||
\version, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY THEREOF.
|
|
||||||
|
|
||||||
\item
|
|
||||||
This License Agreement will automatically terminate upon a material
|
|
||||||
breach of its terms and conditions.
|
|
||||||
|
|
||||||
\item
|
|
||||||
Nothing in this License Agreement shall be deemed to create any
|
|
||||||
relationship of agency, partnership, or joint venture between PSF and
|
|
||||||
Licensee. This License Agreement does not grant permission to use PSF
|
|
||||||
trademarks or trade name in a trademark sense to endorse or promote
|
|
||||||
products or services of Licensee, or any third party.
|
|
||||||
|
|
||||||
\item
|
|
||||||
By copying, installing or otherwise using Python \version, Licensee
|
|
||||||
agrees to be bound by the terms and conditions of this License
|
|
||||||
Agreement.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
|
|
||||||
\centerline{\strong{BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0}}
|
|
||||||
|
|
||||||
\centerline{\strong{BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1}}
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item
|
|
||||||
This LICENSE AGREEMENT is between BeOpen.com (``BeOpen''), having an
|
|
||||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
|
||||||
Individual or Organization (``Licensee'') accessing and otherwise
|
|
||||||
using this software in source or binary form and its associated
|
|
||||||
documentation (``the Software'').
|
|
||||||
|
|
||||||
\item
|
|
||||||
Subject to the terms and conditions of this BeOpen Python License
|
|
||||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
|
||||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
|
||||||
and/or display publicly, prepare derivative works, distribute, and
|
|
||||||
otherwise use the Software alone or in any derivative version,
|
|
||||||
provided, however, that the BeOpen Python License is retained in the
|
|
||||||
Software, alone or in any derivative version prepared by Licensee.
|
|
||||||
|
|
||||||
\item
|
|
||||||
BeOpen is making the Software available to Licensee on an ``AS IS''
|
|
||||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
|
||||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
|
||||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
||||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
|
||||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
|
||||||
|
|
||||||
\item
|
|
||||||
BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
|
||||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
|
||||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
|
||||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
|
||||||
|
|
||||||
\item
|
|
||||||
This License Agreement will automatically terminate upon a material
|
|
||||||
breach of its terms and conditions.
|
|
||||||
|
|
||||||
\item
|
|
||||||
This License Agreement shall be governed by and interpreted in all
|
|
||||||
respects by the law of the State of California, excluding conflict of
|
|
||||||
law provisions. Nothing in this License Agreement shall be deemed to
|
|
||||||
create any relationship of agency, partnership, or joint venture
|
|
||||||
between BeOpen and Licensee. This License Agreement does not grant
|
|
||||||
permission to use BeOpen trademarks or trade names in a trademark
|
|
||||||
sense to endorse or promote products or services of Licensee, or any
|
|
||||||
third party. As an exception, the ``BeOpen Python'' logos available
|
|
||||||
at http://www.pythonlabs.com/logos.html may be used according to the
|
|
||||||
permissions granted on that web page.
|
|
||||||
|
|
||||||
\item
|
|
||||||
By copying, installing or otherwise using the software, Licensee
|
|
||||||
agrees to be bound by the terms and conditions of this License
|
|
||||||
Agreement.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
|
|
||||||
\centerline{\strong{CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1}}
|
|
||||||
|
|
||||||
\begin{enumerate}
|
|
||||||
\item
|
|
||||||
This LICENSE AGREEMENT is between the Corporation for National
|
|
||||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
|
||||||
Reston, VA 20191 (``CNRI''), and the Individual or Organization
|
|
||||||
(``Licensee'') accessing and otherwise using Python 1.6.1 software in
|
|
||||||
source or binary form and its associated documentation.
|
|
||||||
|
|
||||||
\item
|
|
||||||
Subject to the terms and conditions of this License Agreement, CNRI
|
|
||||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
|
||||||
license to reproduce, analyze, test, perform and/or display publicly,
|
|
||||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
|
||||||
alone or in any derivative version, provided, however, that CNRI's
|
|
||||||
License Agreement and CNRI's notice of copyright, i.e., ``Copyright
|
|
||||||
\copyright{} 1995-2001 Corporation for National Research Initiatives;
|
|
||||||
All Rights Reserved'' are retained in Python 1.6.1 alone or in any
|
|
||||||
derivative version prepared by Licensee. Alternately, in lieu of
|
|
||||||
CNRI's License Agreement, Licensee may substitute the following text
|
|
||||||
(omitting the quotes): ``Python 1.6.1 is made available subject to the
|
|
||||||
terms and conditions in CNRI's License Agreement. This Agreement
|
|
||||||
together with Python 1.6.1 may be located on the Internet using the
|
|
||||||
following unique, persistent identifier (known as a handle):
|
|
||||||
1895.22/1013. This Agreement may also be obtained from a proxy server
|
|
||||||
on the Internet using the following URL:
|
|
||||||
\url{http://hdl.handle.net/1895.22/1013}.''
|
|
||||||
|
|
||||||
\item
|
|
||||||
In the event Licensee prepares a derivative work that is based on
|
|
||||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
|
||||||
the derivative work available to others as provided herein, then
|
|
||||||
Licensee hereby agrees to include in any such work a brief summary of
|
|
||||||
the changes made to Python 1.6.1.
|
|
||||||
|
|
||||||
\item
|
|
||||||
CNRI is making Python 1.6.1 available to Licensee on an ``AS IS''
|
|
||||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
|
||||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
|
||||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
||||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
|
||||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
|
||||||
|
|
||||||
\item
|
|
||||||
CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
|
||||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
|
||||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
|
||||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
|
||||||
|
|
||||||
\item
|
|
||||||
This License Agreement will automatically terminate upon a material
|
|
||||||
breach of its terms and conditions.
|
|
||||||
|
|
||||||
\item
|
|
||||||
This License Agreement shall be governed by the federal
|
|
||||||
intellectual property law of the United States, including without
|
|
||||||
limitation the federal copyright law, and, to the extent such
|
|
||||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
|
||||||
Virginia, excluding Virginia's conflict of law provisions.
|
|
||||||
Notwithstanding the foregoing, with regard to derivative works based
|
|
||||||
on Python 1.6.1 that incorporate non-separable material that was
|
|
||||||
previously distributed under the GNU General Public License (GPL), the
|
|
||||||
law of the Commonwealth of Virginia shall govern this License
|
|
||||||
Agreement only as to issues arising under or with respect to
|
|
||||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
|
||||||
License Agreement shall be deemed to create any relationship of
|
|
||||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
|
||||||
License Agreement does not grant permission to use CNRI trademarks or
|
|
||||||
trade name in a trademark sense to endorse or promote products or
|
|
||||||
services of Licensee, or any third party.
|
|
||||||
|
|
||||||
\item
|
|
||||||
By clicking on the ``ACCEPT'' button where indicated, or by copying,
|
|
||||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
|
||||||
bound by the terms and conditions of this License Agreement.
|
|
||||||
\end{enumerate}
|
|
||||||
|
|
||||||
\centerline{ACCEPT}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\centerline{\strong{CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2}}
|
|
||||||
|
|
||||||
Copyright \copyright{} 1991 - 1995, Stichting Mathematisch Centrum
|
|
||||||
Amsterdam, The Netherlands. All rights reserved.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software and its
|
|
||||||
documentation for any purpose and without fee is hereby granted,
|
|
||||||
provided that the above copyright notice appear in all copies and that
|
|
||||||
both that copyright notice and this permission notice appear in
|
|
||||||
supporting documentation, and that the name of Stichting Mathematisch
|
|
||||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
|
||||||
distribution of the software without specific, written prior
|
|
||||||
permission.
|
|
||||||
|
|
||||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
|
||||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
|
||||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
||||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -1,40 +0,0 @@
|
|||||||
% Created by Fred L. Drake, Jr. <fdrake@acm.org>, as part of the
|
|
||||||
% Python Documentation Project.
|
|
||||||
%
|
|
||||||
% Define some simple markup for the LaTeX command documentation:
|
|
||||||
|
|
||||||
\ProvidesPackage{ltxmarkup}
|
|
||||||
\RequirePackage{python} % fulllineitems environment
|
|
||||||
|
|
||||||
% These two macros are used in constructing the last parameter to the
|
|
||||||
% envdesc and macrodesc environments.
|
|
||||||
|
|
||||||
\newcommand{\py@ltx@optparam}[1]{{[}\var{#1}{]}}
|
|
||||||
\newcommand{\py@ltx@param}[1]{\{\var{#1}\}}
|
|
||||||
|
|
||||||
\newenvironment{envdesc}[2]{
|
|
||||||
\begin{fulllineitems}
|
|
||||||
\item[\code{\e begin\{{\bfseries #1}\}{%
|
|
||||||
\let\op=\py@ltx@optparam%
|
|
||||||
\let\p=\py@ltx@param%
|
|
||||||
\let\unspecified=\py@unspecified%
|
|
||||||
\let\moreargs=\py@moreargs%
|
|
||||||
#2}}]
|
|
||||||
\item[\code{\e end\{{\bfseries #1}\}}]
|
|
||||||
\index{#1 environment@\py@idxcode{#1} environment}
|
|
||||||
\index{environments!#1@\py@idxcode{#1}}
|
|
||||||
}{\end{fulllineitems}}
|
|
||||||
|
|
||||||
\newenvironment{macrodesc}[2]{
|
|
||||||
\begin{fulllineitems}
|
|
||||||
\item[\code{{\e\bfseries#1}{%
|
|
||||||
\let\op=\py@ltx@optparam%
|
|
||||||
\let\p=\py@ltx@param%
|
|
||||||
\let\unspecified=\py@unspecified%
|
|
||||||
\let\moreargs=\py@moreargs%
|
|
||||||
#2}}]
|
|
||||||
\index{#1@\py@idxcode{#1}}
|
|
||||||
}{\end{fulllineitems}}
|
|
||||||
|
|
||||||
\newcommand{\env}[1]{\code{#1}}
|
|
||||||
\newcommand{\macro}[1]{\code{\e#1}}
|
|
@ -1,152 +0,0 @@
|
|||||||
%
|
|
||||||
% manual.cls for the Python documentation
|
|
||||||
%
|
|
||||||
|
|
||||||
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
|
|
||||||
\ProvidesClass{manual}
|
|
||||||
[1998/03/03 Document class (Python manual)]
|
|
||||||
|
|
||||||
\RequirePackage{pypaper}
|
|
||||||
|
|
||||||
% Change the options here to get a different set of basic options, but only
|
|
||||||
% if you have to. Paper and font size should be adjusted in pypaper.sty.
|
|
||||||
%
|
|
||||||
\LoadClass[\py@paper,\py@ptsize,twoside,openright]{report}
|
|
||||||
|
|
||||||
\setcounter{secnumdepth}{2}
|
|
||||||
|
|
||||||
% Optional packages:
|
|
||||||
%
|
|
||||||
% If processing of these documents fails at your TeX installation,
|
|
||||||
% these may be commented out (independently) to make things work.
|
|
||||||
% These are both supplied with the current version of the teTeX
|
|
||||||
% distribution.
|
|
||||||
%
|
|
||||||
% The "fancyhdr" package makes nicer page footers reasonable to
|
|
||||||
% implement, and is used to put the chapter and section information in
|
|
||||||
% the footers.
|
|
||||||
%
|
|
||||||
\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.}
|
|
||||||
|
|
||||||
|
|
||||||
% Required packages:
|
|
||||||
%
|
|
||||||
% The "fncychap" package is used to get the nice chapter headers. The
|
|
||||||
% .sty file is distributed with Python, so you should not need to disable
|
|
||||||
% it. You'd also end up with a mixed page style; uglier than stock LaTeX!
|
|
||||||
%
|
|
||||||
\RequirePackage[Bjarne]{fncychap}\typeout{Using fancy chapter headings.}
|
|
||||||
% Do horizontal rules it this way to match:
|
|
||||||
\newcommand{\py@doHorizontalRule}{\mghrulefill{\RW}}
|
|
||||||
%
|
|
||||||
%
|
|
||||||
% This gives us all the Python-specific markup that we really want.
|
|
||||||
% This should come last. Do not change this.
|
|
||||||
%
|
|
||||||
\RequirePackage{python}
|
|
||||||
|
|
||||||
% support for module synopsis sections:
|
|
||||||
\newcommand{\py@ModSynopsisFilename}{\jobname\thechapter.syn}
|
|
||||||
\let\py@OldChapter=\chapter
|
|
||||||
\renewcommand{\chapter}{
|
|
||||||
\py@ProcessModSynopsis
|
|
||||||
\py@closeModSynopsisFile
|
|
||||||
\py@OldChapter
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
% Change the title page to look a bit better, and fit in with the
|
|
||||||
% fncychap ``Bjarne'' style a bit better.
|
|
||||||
%
|
|
||||||
\renewcommand{\maketitle}{%
|
|
||||||
\begin{titlepage}%
|
|
||||||
\let\footnotesize\small
|
|
||||||
\let\footnoterule\relax
|
|
||||||
\py@doHorizontalRule%
|
|
||||||
\@ifundefined{pdfinfo}{}{{
|
|
||||||
% This \def is required to deal with multi-line authors; it
|
|
||||||
% changes \\ to ', ' (comma-space), making it pass muster for
|
|
||||||
% generating document info in the PDF file.
|
|
||||||
\def\\{, }
|
|
||||||
\pdfinfo{
|
|
||||||
/Author (\@author)
|
|
||||||
/Title (\@title)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
\begin{flushright}%
|
|
||||||
{\rm\Huge\py@HeaderFamily \@title \par}%
|
|
||||||
{\em\LARGE\py@HeaderFamily \py@release\releaseinfo \par}
|
|
||||||
\vfill
|
|
||||||
{\LARGE\py@HeaderFamily \@author \par}
|
|
||||||
\vfill\vfill
|
|
||||||
{\large
|
|
||||||
\@date \par
|
|
||||||
\vfill
|
|
||||||
\py@authoraddress \par
|
|
||||||
}%
|
|
||||||
\end{flushright}%\par
|
|
||||||
\@thanks
|
|
||||||
\end{titlepage}%
|
|
||||||
\setcounter{footnote}{0}%
|
|
||||||
\let\thanks\relax\let\maketitle\relax
|
|
||||||
\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
% Catch the end of the {abstract} environment, but here make sure the
|
|
||||||
% abstract is followed by a blank page if the 'openright' option is used.
|
|
||||||
%
|
|
||||||
\let\py@OldEndAbstract=\endabstract
|
|
||||||
\renewcommand{\endabstract}{
|
|
||||||
\if@openright
|
|
||||||
\ifodd\value{page}
|
|
||||||
\typeout{Adding blank page after the abstract.}
|
|
||||||
\vfil\pagebreak
|
|
||||||
\fi
|
|
||||||
\fi
|
|
||||||
\py@OldEndAbstract
|
|
||||||
}
|
|
||||||
|
|
||||||
% This wraps the \tableofcontents macro with all the magic to get the
|
|
||||||
% spacing right and have the right number of pages if the 'openright'
|
|
||||||
% option has been used. This eliminates a fair amount of crud in the
|
|
||||||
% individual document files.
|
|
||||||
%
|
|
||||||
\let\py@OldTableofcontents=\tableofcontents
|
|
||||||
\renewcommand{\tableofcontents}{%
|
|
||||||
\setcounter{page}{1}%
|
|
||||||
\pagebreak%
|
|
||||||
\pagestyle{plain}%
|
|
||||||
{%
|
|
||||||
\parskip = 0mm%
|
|
||||||
\py@OldTableofcontents%
|
|
||||||
\if@openright%
|
|
||||||
\ifodd\value{page}%
|
|
||||||
\typeout{Adding blank page after the table of contents.}%
|
|
||||||
\pagebreak\hspace{0pt}%
|
|
||||||
\fi%
|
|
||||||
\fi%
|
|
||||||
\cleardoublepage%
|
|
||||||
}%
|
|
||||||
\pagenumbering{arabic}%
|
|
||||||
\@ifundefined{fancyhf}{}{\pagestyle{normal}}%
|
|
||||||
\py@doing@page@targetstrue%
|
|
||||||
}
|
|
||||||
% This is needed to get the width of the section # area wide enough in the
|
|
||||||
% library reference. Doing it here keeps it the same for all the manuals.
|
|
||||||
%
|
|
||||||
\renewcommand*\l@section{\@dottedtocline{1}{1.5em}{2.6em}}
|
|
||||||
\renewcommand*\l@subsection{\@dottedtocline{2}{4.1em}{3.5em}}
|
|
||||||
\setcounter{tocdepth}{1}
|
|
||||||
|
|
||||||
|
|
||||||
% Fix the theindex environment to add an entry to the Table of
|
|
||||||
% Contents; this is much nicer than just having to jump to the end of
|
|
||||||
% the book and flip around, especially with multiple indexes.
|
|
||||||
%
|
|
||||||
\let\py@OldTheindex=\theindex
|
|
||||||
\renewcommand{\theindex}{
|
|
||||||
\cleardoublepage
|
|
||||||
\py@OldTheindex
|
|
||||||
\addcontentsline{toc}{chapter}{\indexname}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
%
|
|
||||||
% Change this to say a4paper instead of letterpaper if you want A4. These
|
|
||||||
% are the latex defaults.
|
|
||||||
%
|
|
||||||
\newcommand{\py@paper}{letterpaper}
|
|
||||||
\newcommand{\py@ptsize}{11pt}
|
|
||||||
|
|
||||||
% These set up the fonts for the documents.
|
|
||||||
%
|
|
||||||
% The "times" package makes the default font the PostScript Times
|
|
||||||
% font, which makes for smaller PostScript and a font that more people
|
|
||||||
% like.
|
|
||||||
%
|
|
||||||
% The "avant" package causes the AvantGarde font to be used for
|
|
||||||
% sans-serif text, instead of the uglier Helvetica set up by the "times"
|
|
||||||
% package.
|
|
||||||
%
|
|
||||||
% \RequirePackage{times}\typeout{Using Times instead of Computer Modern.}
|
|
@ -1,11 +0,0 @@
|
|||||||
line_max 100
|
|
||||||
headings_flag 1
|
|
||||||
heading_prefix " \\bigletter "
|
|
||||||
|
|
||||||
preamble "\\begin{theindex}
|
|
||||||
\\def\\bigletter#1{{\\Large\\sffamily#1}\\nopagebreak\\vspace{1mm}}
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
symhead_positive "{Symbols}"
|
|
||||||
numhead_positive "{Numbers}"
|
|
@ -1,61 +0,0 @@
|
|||||||
\label{reporting-bugs}
|
|
||||||
|
|
||||||
Python is a mature programming language which has established a
|
|
||||||
reputation for stability. In order to maintain this reputation, the
|
|
||||||
developers would like to know of any deficiencies you find in Python
|
|
||||||
or its documentation.
|
|
||||||
|
|
||||||
Before submitting a report, you will be required to log into SourceForge;
|
|
||||||
this will make it possible for the developers to contact you
|
|
||||||
for additional information if needed. It is not possible to submit a
|
|
||||||
bug report anonymously.
|
|
||||||
|
|
||||||
All bug reports should be submitted via the Python Bug Tracker on
|
|
||||||
SourceForge (\url{http://sourceforge.net/bugs/?group_id=5470}). The
|
|
||||||
bug tracker offers a Web form which allows pertinent information to be
|
|
||||||
entered and submitted to the developers.
|
|
||||||
|
|
||||||
The first step in filing a report is to determine whether the problem
|
|
||||||
has already been reported. The advantage in doing so, aside from
|
|
||||||
saving the developers time, is that you learn what has been done to
|
|
||||||
fix it; it may be that the problem has already been fixed for the next
|
|
||||||
release, or additional information is needed (in which case you are
|
|
||||||
welcome to provide it if you can!). To do this, search the bug
|
|
||||||
database using the search box near the bottom of the page.
|
|
||||||
|
|
||||||
If the problem you're reporting is not already in the bug tracker, go
|
|
||||||
back to the Python Bug Tracker
|
|
||||||
(\url{http://sourceforge.net/bugs/?group_id=5470}). Select the
|
|
||||||
``Submit a Bug'' link at the top of the page to open the bug reporting
|
|
||||||
form.
|
|
||||||
|
|
||||||
The submission form has a number of fields. The only fields that are
|
|
||||||
required are the ``Summary'' and ``Details'' fields. For the summary,
|
|
||||||
enter a \emph{very} short description of the problem; less than ten
|
|
||||||
words is good. In the Details field, describe the problem in detail,
|
|
||||||
including what you expected to happen and what did happen. Be sure to
|
|
||||||
include the version of Python you used, whether any extension modules
|
|
||||||
were involved, and what hardware and software platform you were using
|
|
||||||
(including version information as appropriate).
|
|
||||||
|
|
||||||
The only other field that you may want to set is the ``Category''
|
|
||||||
field, which allows you to place the bug report into a broad category
|
|
||||||
(such as ``Documentation'' or ``Library'').
|
|
||||||
|
|
||||||
Each bug report will be assigned to a developer who will determine
|
|
||||||
what needs to be done to correct the problem. You will
|
|
||||||
receive an update each time action is taken on the bug.
|
|
||||||
|
|
||||||
|
|
||||||
\begin{seealso}
|
|
||||||
\seetitle[http://www-mice.cs.ucl.ac.uk/multimedia/software/documentation/ReportingBugs.html]{How
|
|
||||||
to Report Bugs Effectively}{Article which goes into some
|
|
||||||
detail about how to create a useful bug report. This
|
|
||||||
describes what kind of information is useful and why it is
|
|
||||||
useful.}
|
|
||||||
|
|
||||||
\seetitle[http://www.mozilla.org/quality/bug-writing-guidelines.html]{Bug
|
|
||||||
Writing Guidelines}{Information about writing a good bug
|
|
||||||
report. Some of this is specific to the Mozilla project, but
|
|
||||||
describes general good practices.}
|
|
||||||
\end{seealso}
|
|
@ -1,171 +0,0 @@
|
|||||||
137,153d136
|
|
||||||
< % Set up abstract ways to get the normal and smaller font sizes that
|
|
||||||
< % work even in footnote context.
|
|
||||||
< \newif\ifpy@infootnote \py@infootnotefalse
|
|
||||||
< \let\py@oldmakefntext\@makefntext
|
|
||||||
< \def\@makefntext#1{%
|
|
||||||
< \bgroup%
|
|
||||||
< \py@infootnotetrue
|
|
||||||
< \py@oldmakefntext{#1}%
|
|
||||||
< \egroup%
|
|
||||||
< }
|
|
||||||
< \def\py@defaultsize{%
|
|
||||||
< \ifpy@infootnote\footnotesize\else\normalsize\fi%
|
|
||||||
< }
|
|
||||||
< \def\py@smallsize{%
|
|
||||||
< \ifpy@infootnote\scriptsize\else\small\fi%
|
|
||||||
< }
|
|
||||||
<
|
|
||||||
201,208c184,187
|
|
||||||
< \setlength{\parindent}{1cm}%
|
|
||||||
< % Calculate the text width for the minipage:
|
|
||||||
< \setlength{\py@codewidth}{\linewidth}%
|
|
||||||
< \addtolength{\py@codewidth}{-\parindent}%
|
|
||||||
< %
|
|
||||||
< \par\indent%
|
|
||||||
< \begin{minipage}[t]{\py@codewidth}%
|
|
||||||
< \small%
|
|
||||||
---
|
|
||||||
> \begingroup%
|
|
||||||
> \small%
|
|
||||||
> \begin{list}{}{\setlength{\leftmargin}{1cm}}
|
|
||||||
> \item%
|
|
||||||
213c192,193
|
|
||||||
< \end{minipage}%
|
|
||||||
---
|
|
||||||
> \end{list}%
|
|
||||||
> \endgroup
|
|
||||||
216,221c196
|
|
||||||
< {\setlength{\parindent}{1cm}%
|
|
||||||
< % Calculate the text width for the minipage:
|
|
||||||
< \setlength{\py@codewidth}{\linewidth}%
|
|
||||||
< \addtolength{\py@codewidth}{-\parindent}%
|
|
||||||
< %
|
|
||||||
< \small%
|
|
||||||
---
|
|
||||||
> {\small%
|
|
||||||
601,610d575
|
|
||||||
<
|
|
||||||
< \newlength{\py@argswidth}
|
|
||||||
< \newcommand{\py@sigparams}[1]{%
|
|
||||||
< \parbox[t]{\py@argswidth}{\py@varvars{#1}\code{)}}}
|
|
||||||
< \newcommand{\py@sigline}[2]{%
|
|
||||||
< \settowidth{\py@argswidth}{#1\code{(}}%
|
|
||||||
< \addtolength{\py@argswidth}{-2\py@argswidth}%
|
|
||||||
< \addtolength{\py@argswidth}{\textwidth}%
|
|
||||||
< \item[#1\code{(}\py@sigparams{#2}]}
|
|
||||||
<
|
|
||||||
615,618d579
|
|
||||||
< \newcommand{\cfuncline}[3]{
|
|
||||||
< \py@sigline{\code{#1 \bfcode{#2}}}{#3}%
|
|
||||||
< \index{#2@{\py@idxcode{#2()}}}
|
|
||||||
< }
|
|
||||||
621c582
|
|
||||||
< \cfuncline{#2}{#3}{#4}
|
|
||||||
---
|
|
||||||
> \item[\code{#2 \bfcode{#3}(\py@varvars{#4})}\index{#3@{\py@idxcode{#3()}}}]
|
|
||||||
646,656d606
|
|
||||||
< % C type fields ----------------------------------------------------------
|
|
||||||
< % \begin{cmemberdesc}{container type}{ctype}{membername}
|
|
||||||
< \newcommand{\cmemberline}[3]{
|
|
||||||
< \item[\code{#2 \bfcode{#3}}]
|
|
||||||
< \index{#3@{\py@idxcode{#3}} (#1 member)}
|
|
||||||
< }
|
|
||||||
< \newenvironment{cmemberdesc}[3]{
|
|
||||||
< \begin{fulllineitems}
|
|
||||||
< \cmemberline{#1}{#2}{#3}
|
|
||||||
< }{\end{fulllineitems}}
|
|
||||||
<
|
|
||||||
658c608
|
|
||||||
< % \begin{csimplemacrodesc}{name}
|
|
||||||
---
|
|
||||||
> % \begin{csimplemacro}{name}
|
|
||||||
676,677c626
|
|
||||||
< \newcommand{\funclineni}[2]{%
|
|
||||||
< \py@sigline{\bfcode{#1}}{#2}}
|
|
||||||
---
|
|
||||||
> \newcommand{\funclineni}[2]{\item[\code{\bfcode{#1}(\py@varvars{#2})}]}
|
|
||||||
689,690c638,639
|
|
||||||
< \py@sigline{\strong{class }\bfcode{#1}}{#2}%
|
|
||||||
< \index{#1@{\py@idxcode{#1}} (class in \py@thismodule)}
|
|
||||||
---
|
|
||||||
> \item[\strong{class }\code{\bfcode{#1}(\py@varvars{#2})}%
|
|
||||||
> \index{#1@{\py@idxcode{#1}} (class in \py@thismodule)}]
|
|
||||||
708,709c657,658
|
|
||||||
< \py@sigline{\strong{exception }\bfcode{#1}}{#2}%
|
|
||||||
< \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)}
|
|
||||||
---
|
|
||||||
> \item[\strong{exception }\code{\bfcode{#1}(\py@varvars{#2})}%
|
|
||||||
> \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)}]
|
|
||||||
741c690
|
|
||||||
< \py@sigline{\bfcode{#2}}{#3}}
|
|
||||||
---
|
|
||||||
> \item[\code{\bfcode{#2}(\py@varvars{#3})}]}
|
|
||||||
824d772
|
|
||||||
< % \menuselection{Start \sub Programs \sub Python}
|
|
||||||
834d781
|
|
||||||
< \newcommand{\csimplemacro}[1]{\code{#1}}
|
|
||||||
836a784,786
|
|
||||||
> % This weird definition of \var{} allows it to always appear in roman
|
|
||||||
> % italics, and won't get funky in code fragments when we play around
|
|
||||||
> % with fonts. This also works directly in math mode.
|
|
||||||
839c789
|
|
||||||
< \hbox{\py@defaultsize\textrm{\textit{#1\/}}}%
|
|
||||||
---
|
|
||||||
> \hbox{\normalsize\textrm{\textit{#1\/}}}%
|
|
||||||
841c791
|
|
||||||
< \py@defaultsize\textrm{\textit{#1\/}}%
|
|
||||||
---
|
|
||||||
> \normalsize\textrm{\textit{#1\/}}%
|
|
||||||
848,849c798,799
|
|
||||||
< \newcommand{\file}[1]{`\filenq{#1}'}
|
|
||||||
< \newcommand{\filenq}[1]{{\py@smallsize\textsf{#1}}}
|
|
||||||
---
|
|
||||||
> \newcommand{\file}[1]{`{\textsf{#1}}'}
|
|
||||||
> \newcommand{\filenq}[1]{{\textsf{#1}}}
|
|
||||||
858c808
|
|
||||||
< \py@smallsize\sf #1%
|
|
||||||
---
|
|
||||||
> \small\sf #1%
|
|
||||||
863c813
|
|
||||||
< \newcommand{\url}[1]{\mbox{\py@smallsize\textsf{#1}}}
|
|
||||||
---
|
|
||||||
> \newcommand{\url}[1]{\mbox{\small\textsf{#1}}}
|
|
||||||
865,866c815,816
|
|
||||||
< \newcommand{\email}[1]{{\py@smallsize\textsf{#1}}}
|
|
||||||
< \newcommand{\newsgroup}[1]{{\py@smallsize\textsf{#1}}}
|
|
||||||
---
|
|
||||||
> \newcommand{\email}[1]{{\small\textsf{#1}}}
|
|
||||||
> \newcommand{\newsgroup}[1]{{\small\textsf{#1}}}
|
|
||||||
902,903c852,853
|
|
||||||
< \newcommand{\mailheader}[1]{{\py@smallsize\textsf{#1:}}}
|
|
||||||
< \newcommand{\mimetype}[1]{{\py@smallsize\textsf{#1}}}
|
|
||||||
---
|
|
||||||
> \newcommand{\mailheader}[1]{{\small\textsf{#1:}}}
|
|
||||||
> \newcommand{\mimetype}[1]{{\small\textsf{#1}}}
|
|
||||||
907c857
|
|
||||||
< {\py@defaultsize\code{#1}}%
|
|
||||||
---
|
|
||||||
> {\normalsize\code{#1}}%
|
|
||||||
1105,1125d1054
|
|
||||||
<
|
|
||||||
< % XXX Don't think we can use this yet, though it cleans up some
|
|
||||||
< % tedious markup. There's no equivalent for the HTML transform yet,
|
|
||||||
< % and that needs to exist. I don't know how to write it.
|
|
||||||
< %
|
|
||||||
< % This should really have something that makes it easier to bind a
|
|
||||||
< % table's ``Notes'' column and an associated tablenotes environment,
|
|
||||||
< % and generates the right magic for getting the numbers right in the
|
|
||||||
< % table.
|
|
||||||
< %
|
|
||||||
< % So this is quite incomplete.
|
|
||||||
< %
|
|
||||||
< \newcounter{py@tablenotescounter}
|
|
||||||
< \newenvironment{tablenotes}{%
|
|
||||||
< \noindent Notes:
|
|
||||||
< \par
|
|
||||||
< \setcounter{py@tablenotescounter}{0}
|
|
||||||
< \begin{list}{(\arabic{py@tablenotescounter})}%
|
|
||||||
< {\usecounter{py@tablenotescounter}}
|
|
||||||
< }{\end{list}}
|
|
||||||
<
|
|
@ -1,76 +0,0 @@
|
|||||||
typedef struct _typeobject {
|
|
||||||
PyObject_VAR_HEAD
|
|
||||||
char *tp_name; /* For printing, in format "<module>.<name>" */
|
|
||||||
int tp_basicsize, tp_itemsize; /* For allocation */
|
|
||||||
|
|
||||||
/* Methods to implement standard operations */
|
|
||||||
|
|
||||||
destructor tp_dealloc;
|
|
||||||
printfunc tp_print;
|
|
||||||
getattrfunc tp_getattr;
|
|
||||||
setattrfunc tp_setattr;
|
|
||||||
cmpfunc tp_compare;
|
|
||||||
reprfunc tp_repr;
|
|
||||||
|
|
||||||
/* Method suites for standard classes */
|
|
||||||
|
|
||||||
PyNumberMethods *tp_as_number;
|
|
||||||
PySequenceMethods *tp_as_sequence;
|
|
||||||
PyMappingMethods *tp_as_mapping;
|
|
||||||
|
|
||||||
/* More standard operations (here for binary compatibility) */
|
|
||||||
|
|
||||||
hashfunc tp_hash;
|
|
||||||
ternaryfunc tp_call;
|
|
||||||
reprfunc tp_str;
|
|
||||||
getattrofunc tp_getattro;
|
|
||||||
setattrofunc tp_setattro;
|
|
||||||
|
|
||||||
/* Functions to access object as input/output buffer */
|
|
||||||
PyBufferProcs *tp_as_buffer;
|
|
||||||
|
|
||||||
/* Flags to define presence of optional/expanded features */
|
|
||||||
long tp_flags;
|
|
||||||
|
|
||||||
char *tp_doc; /* Documentation string */
|
|
||||||
|
|
||||||
/* Assigned meaning in release 2.0 */
|
|
||||||
/* call function for all accessible objects */
|
|
||||||
traverseproc tp_traverse;
|
|
||||||
|
|
||||||
/* delete references to contained objects */
|
|
||||||
inquiry tp_clear;
|
|
||||||
|
|
||||||
/* Assigned meaning in release 2.1 */
|
|
||||||
/* rich comparisons */
|
|
||||||
richcmpfunc tp_richcompare;
|
|
||||||
|
|
||||||
/* weak reference enabler */
|
|
||||||
long tp_weaklistoffset;
|
|
||||||
|
|
||||||
/* Added in release 2.2 */
|
|
||||||
/* Iterators */
|
|
||||||
getiterfunc tp_iter;
|
|
||||||
iternextfunc tp_iternext;
|
|
||||||
|
|
||||||
/* Attribute descriptor and subclassing stuff */
|
|
||||||
struct PyMethodDef *tp_methods;
|
|
||||||
struct PyMemberDef *tp_members;
|
|
||||||
struct PyGetSetDef *tp_getset;
|
|
||||||
struct _typeobject *tp_base;
|
|
||||||
PyObject *tp_dict;
|
|
||||||
descrgetfunc tp_descr_get;
|
|
||||||
descrsetfunc tp_descr_set;
|
|
||||||
long tp_dictoffset;
|
|
||||||
initproc tp_init;
|
|
||||||
allocfunc tp_alloc;
|
|
||||||
newfunc tp_new;
|
|
||||||
freefunc tp_free; /* Low-level free-memory routine */
|
|
||||||
inquiry tp_is_gc; /* For PyObject_IS_GC */
|
|
||||||
PyObject *tp_bases;
|
|
||||||
PyObject *tp_mro; /* method resolution order */
|
|
||||||
PyObject *tp_cache;
|
|
||||||
PyObject *tp_subclasses;
|
|
||||||
PyObject *tp_weaklist;
|
|
||||||
|
|
||||||
} PyTypeObject;
|
|
@ -1,71 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
"""Add reference count annotations to the Python/C API Reference."""
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import refcounts
|
|
||||||
|
|
||||||
|
|
||||||
PREFIX_1 = r"\begin{cfuncdesc}{PyObject*}{"
|
|
||||||
PREFIX_2 = r"\begin{cfuncdesc}{PyVarObject*}{"
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
rcfile = os.path.join(os.path.dirname(refcounts.__file__), os.pardir,
|
|
||||||
"api", "refcounts.dat")
|
|
||||||
outfile = "-"
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "o:r:", ["output=", "refcounts="])
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ("-o", "--output"):
|
|
||||||
outfile = arg
|
|
||||||
elif opt in ("-r", "--refcounts"):
|
|
||||||
rcfile = arg
|
|
||||||
rcdict = refcounts.load(rcfile)
|
|
||||||
if outfile == "-":
|
|
||||||
output = sys.stdout
|
|
||||||
else:
|
|
||||||
output = open(outfile, "w")
|
|
||||||
if not args:
|
|
||||||
args = ["-"]
|
|
||||||
for infile in args:
|
|
||||||
if infile == "-":
|
|
||||||
input = sys.stdin
|
|
||||||
else:
|
|
||||||
input = open(infile)
|
|
||||||
while 1:
|
|
||||||
line = input.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
prefix = None
|
|
||||||
if line.startswith(PREFIX_1):
|
|
||||||
prefix = PREFIX_1
|
|
||||||
elif line.startswith(PREFIX_2):
|
|
||||||
prefix = PREFIX_2
|
|
||||||
if prefix:
|
|
||||||
s = line[len(prefix):].split('}', 1)[0]
|
|
||||||
try:
|
|
||||||
info = rcdict[s]
|
|
||||||
except KeyError:
|
|
||||||
sys.stderr.write("No refcount data for %s\n" % s)
|
|
||||||
else:
|
|
||||||
if info.result_type in ("PyObject*", "PyVarObject*"):
|
|
||||||
if info.result_refs is None:
|
|
||||||
rc = "Always \NULL{}"
|
|
||||||
else:
|
|
||||||
rc = info.result_refs and "New" or "Borrowed"
|
|
||||||
rc = rc + " reference"
|
|
||||||
line = (r"\begin{cfuncdesc}[%s]{%s}{"
|
|
||||||
% (rc, info.result_type)) \
|
|
||||||
+ line[len(prefix):]
|
|
||||||
output.write(line)
|
|
||||||
if infile != "-":
|
|
||||||
input.close()
|
|
||||||
if outfile != "-":
|
|
||||||
output.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,377 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
import string
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
bang_join = "!".join
|
|
||||||
null_join = "".join
|
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
|
||||||
__rmjunk = re.compile("<#\d+#>")
|
|
||||||
|
|
||||||
continuation = 0
|
|
||||||
|
|
||||||
def __init__(self, link, str, seqno):
|
|
||||||
self.links = [link]
|
|
||||||
self.seqno = seqno
|
|
||||||
# remove <#\d+#> left in by moving the data out of LaTeX2HTML
|
|
||||||
str = self.__rmjunk.sub('', str)
|
|
||||||
# build up the text
|
|
||||||
self.text = split_entry_text(str)
|
|
||||||
self.key = split_entry_key(str)
|
|
||||||
|
|
||||||
def __cmp__(self, other):
|
|
||||||
"""Comparison operator includes sequence number, for use with
|
|
||||||
list.sort()."""
|
|
||||||
return self.cmp_entry(other) or cmp(self.seqno, other.seqno)
|
|
||||||
|
|
||||||
def cmp_entry(self, other):
|
|
||||||
"""Comparison 'operator' that ignores sequence number."""
|
|
||||||
c = 0
|
|
||||||
for i in range(min(len(self.key), len(other.key))):
|
|
||||||
c = (cmp_part(self.key[i], other.key[i])
|
|
||||||
or cmp_part(self.text[i], other.text[i]))
|
|
||||||
if c:
|
|
||||||
break
|
|
||||||
return c or cmp(self.key, other.key) or cmp(self.text, other.text)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<Node for %s (%s)>" % (bang_join(self.text), self.seqno)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return bang_join(self.key)
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
return "%s\1%s###%s\n" \
|
|
||||||
% ("\1".join(self.links),
|
|
||||||
bang_join(self.text),
|
|
||||||
self.seqno)
|
|
||||||
|
|
||||||
|
|
||||||
def cmp_part(s1, s2):
|
|
||||||
result = cmp(s1, s2)
|
|
||||||
if result == 0:
|
|
||||||
return 0
|
|
||||||
l1 = s1.lower()
|
|
||||||
l2 = s2.lower()
|
|
||||||
minlen = min(len(s1), len(s2))
|
|
||||||
if len(s1) < len(s2) and l1 == l2[:len(s1)]:
|
|
||||||
result = -1
|
|
||||||
elif len(s2) < len(s1) and l2 == l1[:len(s2)]:
|
|
||||||
result = 1
|
|
||||||
else:
|
|
||||||
result = cmp(l1, l2) or cmp(s1, s2)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def split_entry(str, which):
|
|
||||||
stuff = []
|
|
||||||
parts = str.split('!')
|
|
||||||
parts = [part.split('@') for part in parts]
|
|
||||||
for entry in parts:
|
|
||||||
if len(entry) != 1:
|
|
||||||
key = entry[which]
|
|
||||||
else:
|
|
||||||
key = entry[0]
|
|
||||||
stuff.append(key)
|
|
||||||
return stuff
|
|
||||||
|
|
||||||
|
|
||||||
_rmtt = re.compile(r"""(.*)<tt(?: class=['"][a-z0-9]+["'])?>(.*)</tt>(.*)$""",
|
|
||||||
re.IGNORECASE)
|
|
||||||
_rmparens = re.compile(r"\(\)")
|
|
||||||
|
|
||||||
def split_entry_key(str):
|
|
||||||
parts = split_entry(str, 1)
|
|
||||||
for i in range(len(parts)):
|
|
||||||
m = _rmtt.match(parts[i])
|
|
||||||
if m:
|
|
||||||
parts[i] = null_join(m.group(1, 2, 3))
|
|
||||||
else:
|
|
||||||
parts[i] = parts[i].lower()
|
|
||||||
# remove '()' from the key:
|
|
||||||
parts[i] = _rmparens.sub('', parts[i])
|
|
||||||
return map(trim_ignored_letters, parts)
|
|
||||||
|
|
||||||
|
|
||||||
def split_entry_text(str):
|
|
||||||
if '<' in str:
|
|
||||||
m = _rmtt.match(str)
|
|
||||||
if m:
|
|
||||||
str = null_join(m.group(1, 2, 3))
|
|
||||||
return split_entry(str, 1)
|
|
||||||
|
|
||||||
|
|
||||||
def load(fp):
|
|
||||||
nodes = []
|
|
||||||
rx = re.compile("(.*)\1(.*)###(.*)$")
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
m = rx.match(line)
|
|
||||||
if m:
|
|
||||||
link, str, seqno = m.group(1, 2, 3)
|
|
||||||
nodes.append(Node(link, str, seqno))
|
|
||||||
return nodes
|
|
||||||
|
|
||||||
|
|
||||||
def trim_ignored_letters(s):
|
|
||||||
# ignore $ to keep environment variables with the
|
|
||||||
# leading letter from the name
|
|
||||||
if s.startswith("$"):
|
|
||||||
return s[1:].lower()
|
|
||||||
else:
|
|
||||||
return s.lower()
|
|
||||||
|
|
||||||
def get_first_letter(s):
|
|
||||||
if s.startswith("<tex2html_percent_mark>"):
|
|
||||||
return "%"
|
|
||||||
else:
|
|
||||||
return trim_ignored_letters(s)[0]
|
|
||||||
|
|
||||||
|
|
||||||
def split_letters(nodes):
|
|
||||||
letter_groups = []
|
|
||||||
if nodes:
|
|
||||||
group = []
|
|
||||||
append = group.append
|
|
||||||
letter = get_first_letter(nodes[0].text[0])
|
|
||||||
letter_groups.append((letter, group))
|
|
||||||
for node in nodes:
|
|
||||||
nletter = get_first_letter(node.text[0])
|
|
||||||
if letter != nletter:
|
|
||||||
letter = nletter
|
|
||||||
group = []
|
|
||||||
letter_groups.append((letter, group))
|
|
||||||
append = group.append
|
|
||||||
append(node)
|
|
||||||
return letter_groups
|
|
||||||
|
|
||||||
|
|
||||||
def group_symbols(groups):
|
|
||||||
entries = []
|
|
||||||
ident_letters = string.ascii_letters + "_"
|
|
||||||
while groups[0][0] not in ident_letters:
|
|
||||||
entries += groups[0][1]
|
|
||||||
del groups[0]
|
|
||||||
if entries:
|
|
||||||
groups.insert(0, ("Symbols", entries))
|
|
||||||
|
|
||||||
|
|
||||||
# need a function to separate the nodes into columns...
|
|
||||||
def split_columns(nodes, columns=1):
|
|
||||||
if columns <= 1:
|
|
||||||
return [nodes]
|
|
||||||
# This is a rough height; we may have to increase to avoid breaks before
|
|
||||||
# a subitem.
|
|
||||||
colheight = int(len(nodes) / columns)
|
|
||||||
numlong = int(len(nodes) % columns)
|
|
||||||
if numlong:
|
|
||||||
colheight = colheight + 1
|
|
||||||
else:
|
|
||||||
numlong = columns
|
|
||||||
cols = []
|
|
||||||
for i in range(numlong):
|
|
||||||
start = i * colheight
|
|
||||||
end = start + colheight
|
|
||||||
cols.append(nodes[start:end])
|
|
||||||
del nodes[:end]
|
|
||||||
colheight = colheight - 1
|
|
||||||
try:
|
|
||||||
numshort = int(len(nodes) / colheight)
|
|
||||||
except ZeroDivisionError:
|
|
||||||
cols = cols + (columns - len(cols)) * [[]]
|
|
||||||
else:
|
|
||||||
for i in range(numshort):
|
|
||||||
start = i * colheight
|
|
||||||
end = start + colheight
|
|
||||||
cols.append(nodes[start:end])
|
|
||||||
#
|
|
||||||
# If items continue across columns, make sure they are marked
|
|
||||||
# as continuations so the user knows to look at the previous column.
|
|
||||||
#
|
|
||||||
for i in range(len(cols) - 1):
|
|
||||||
try:
|
|
||||||
prev = cols[i][-1]
|
|
||||||
next = cols[i + 1][0]
|
|
||||||
except IndexError:
|
|
||||||
return cols
|
|
||||||
else:
|
|
||||||
n = min(len(prev.key), len(next.key))
|
|
||||||
for j in range(n):
|
|
||||||
if prev.key[j] != next.key[j]:
|
|
||||||
break
|
|
||||||
next.continuation = j + 1
|
|
||||||
return cols
|
|
||||||
|
|
||||||
|
|
||||||
DL_LEVEL_INDENT = " "
|
|
||||||
|
|
||||||
def format_column(nodes):
|
|
||||||
strings = ["<dl compact>"]
|
|
||||||
append = strings.append
|
|
||||||
level = 0
|
|
||||||
previous = []
|
|
||||||
for node in nodes:
|
|
||||||
current = node.text
|
|
||||||
count = 0
|
|
||||||
for i in range(min(len(current), len(previous))):
|
|
||||||
if previous[i] != current[i]:
|
|
||||||
break
|
|
||||||
count = i + 1
|
|
||||||
if count > level:
|
|
||||||
append("<dl compact>" * (count - level) + "\n")
|
|
||||||
level = count
|
|
||||||
elif level > count:
|
|
||||||
append("\n")
|
|
||||||
append(level * DL_LEVEL_INDENT)
|
|
||||||
append("</dl>" * (level - count))
|
|
||||||
level = count
|
|
||||||
# else: level == count
|
|
||||||
for i in range(count, len(current) - 1):
|
|
||||||
term = node.text[i]
|
|
||||||
level = level + 1
|
|
||||||
if node.continuation > i:
|
|
||||||
extra = " (continued)"
|
|
||||||
else:
|
|
||||||
extra = ""
|
|
||||||
append("\n<dt>%s%s\n<dd>\n%s<dl compact>"
|
|
||||||
% (term, extra, level * DL_LEVEL_INDENT))
|
|
||||||
append("\n%s<dt>%s%s</a>"
|
|
||||||
% (level * DL_LEVEL_INDENT, node.links[0], node.text[-1]))
|
|
||||||
for link in node.links[1:]:
|
|
||||||
append(",\n%s %s[Link]</a>" % (level * DL_LEVEL_INDENT, link))
|
|
||||||
previous = current
|
|
||||||
append("\n")
|
|
||||||
append("</dl>" * (level + 1))
|
|
||||||
return null_join(strings)
|
|
||||||
|
|
||||||
|
|
||||||
def format_nodes(nodes, columns=1):
|
|
||||||
strings = []
|
|
||||||
append = strings.append
|
|
||||||
if columns > 1:
|
|
||||||
colnos = range(columns)
|
|
||||||
colheight = int(len(nodes) / columns)
|
|
||||||
if len(nodes) % columns:
|
|
||||||
colheight = colheight + 1
|
|
||||||
colwidth = int(100 / columns)
|
|
||||||
append('<table width="100%"><tr valign="top">')
|
|
||||||
for col in split_columns(nodes, columns):
|
|
||||||
append('<td width="%d%%">\n' % colwidth)
|
|
||||||
append(format_column(col))
|
|
||||||
append("\n</td>")
|
|
||||||
append("\n</tr></table>")
|
|
||||||
else:
|
|
||||||
append(format_column(nodes))
|
|
||||||
append("\n<p>\n")
|
|
||||||
return null_join(strings)
|
|
||||||
|
|
||||||
|
|
||||||
def format_letter(letter):
|
|
||||||
if letter == '.':
|
|
||||||
lettername = ". (dot)"
|
|
||||||
elif letter == '_':
|
|
||||||
lettername = "_ (underscore)"
|
|
||||||
else:
|
|
||||||
lettername = letter.capitalize()
|
|
||||||
return "\n<hr>\n<h2><a name=\"letter-%s\">%s</a></h2>\n\n" \
|
|
||||||
% (letter, lettername)
|
|
||||||
|
|
||||||
|
|
||||||
def format_html_letters(nodes, columns, group_symbol_nodes):
|
|
||||||
letter_groups = split_letters(nodes)
|
|
||||||
if group_symbol_nodes:
|
|
||||||
group_symbols(letter_groups)
|
|
||||||
items = []
|
|
||||||
for letter, nodes in letter_groups:
|
|
||||||
s = "<b><a href=\"#letter-%s\">%s</a></b>" % (letter, letter)
|
|
||||||
items.append(s)
|
|
||||||
s = ["<hr><center>\n%s</center>\n" % " |\n".join(items)]
|
|
||||||
for letter, nodes in letter_groups:
|
|
||||||
s.append(format_letter(letter))
|
|
||||||
s.append(format_nodes(nodes, columns))
|
|
||||||
return null_join(s)
|
|
||||||
|
|
||||||
def format_html(nodes, columns):
|
|
||||||
return format_nodes(nodes, columns)
|
|
||||||
|
|
||||||
|
|
||||||
def collapse(nodes):
|
|
||||||
"""Collapse sequences of nodes with matching keys into a single node.
|
|
||||||
Destructive."""
|
|
||||||
if len(nodes) < 2:
|
|
||||||
return
|
|
||||||
prev = nodes[0]
|
|
||||||
i = 1
|
|
||||||
while i < len(nodes):
|
|
||||||
node = nodes[i]
|
|
||||||
if not node.cmp_entry(prev):
|
|
||||||
prev.links.append(node.links[0])
|
|
||||||
del nodes[i]
|
|
||||||
else:
|
|
||||||
i = i + 1
|
|
||||||
prev = node
|
|
||||||
|
|
||||||
|
|
||||||
def dump(nodes, fp):
|
|
||||||
for node in nodes:
|
|
||||||
fp.write(node.dump())
|
|
||||||
|
|
||||||
|
|
||||||
def process_nodes(nodes, columns, letters=0, group_symbol_nodes=0):
|
|
||||||
nodes.sort()
|
|
||||||
collapse(nodes)
|
|
||||||
if letters:
|
|
||||||
return format_html_letters(nodes, columns, group_symbol_nodes)
|
|
||||||
else:
|
|
||||||
return format_html(nodes, columns)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import getopt
|
|
||||||
ifn = "-"
|
|
||||||
ofn = "-"
|
|
||||||
columns = 1
|
|
||||||
letters = 0
|
|
||||||
group_symbol_nodes = 1
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "c:lo:",
|
|
||||||
["columns=", "dont-group-symbols",
|
|
||||||
"group-symbols", "letters", "output="])
|
|
||||||
for opt, val in opts:
|
|
||||||
if opt in ("-o", "--output"):
|
|
||||||
ofn = val
|
|
||||||
elif opt in ("-c", "--columns"):
|
|
||||||
columns = int(val, 10)
|
|
||||||
elif opt in ("-l", "--letters"):
|
|
||||||
letters = 1
|
|
||||||
elif opt == "--group-symbols":
|
|
||||||
group_symbol_nodes = 1
|
|
||||||
elif opt == "--dont-group-symbols":
|
|
||||||
group_symbol_nodes = 0
|
|
||||||
if not args:
|
|
||||||
args = [ifn]
|
|
||||||
nodes = []
|
|
||||||
for fn in args:
|
|
||||||
nodes = nodes + load(open(fn))
|
|
||||||
num_nodes = len(nodes)
|
|
||||||
html = process_nodes(nodes, columns, letters, group_symbol_nodes)
|
|
||||||
program = os.path.basename(sys.argv[0])
|
|
||||||
if ofn == "-":
|
|
||||||
sys.stdout.write(html)
|
|
||||||
sys.stderr.write("\n%s: %d index nodes" % (program, num_nodes))
|
|
||||||
else:
|
|
||||||
open(ofn, "w").write(html)
|
|
||||||
print
|
|
||||||
print "%s: %d index nodes" % (program, num_nodes)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,112 +0,0 @@
|
|||||||
#!/uns/bin/perl
|
|
||||||
|
|
||||||
package checkargs;
|
|
||||||
require 5.004; # uses "for my $var"
|
|
||||||
require Exporter;
|
|
||||||
@ISA = qw(Exporter);
|
|
||||||
@EXPORT = qw(check_args check_args_range check_args_at_least);
|
|
||||||
use strict;
|
|
||||||
use Carp;
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
checkargs -- Provide rudimentary argument checking for perl5 functions
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
check_args(cArgsExpected, @_)
|
|
||||||
check_args_range(cArgsMin, cArgsMax, @_)
|
|
||||||
check_args_at_least(cArgsMin, @_)
|
|
||||||
where "@_" should be supplied literally.
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
As the first line of user-written subroutine foo, do one of the following:
|
|
||||||
|
|
||||||
my ($arg1, $arg2) = check_args(2, @_);
|
|
||||||
my ($arg1, @rest) = check_args_range(1, 4, @_);
|
|
||||||
my ($arg1, @rest) = check_args_at_least(1, @_);
|
|
||||||
my @args = check_args_at_least(0, @_);
|
|
||||||
|
|
||||||
These functions may also be called for side effect (put a call to one
|
|
||||||
of the functions near the beginning of the subroutine), but using the
|
|
||||||
argument checkers to set the argument list is the recommended usage.
|
|
||||||
|
|
||||||
The number of arguments and their definedness are checked; if the wrong
|
|
||||||
number are received, the program exits with an error message.
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Michael D. Ernst <F<mernst@cs.washington.edu>>
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
## Need to check that use of caller(1) really gives desired results.
|
|
||||||
## Need to give input chunk information.
|
|
||||||
## Is this obviated by Perl 5.003's declarations? Not entirely, I think.
|
|
||||||
|
|
||||||
sub check_args ( $@ )
|
|
||||||
{
|
|
||||||
my ($num_formals, @args) = @_;
|
|
||||||
my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1);
|
|
||||||
if (@_ < 1) { croak "check_args needs at least 7 args, got ", scalar(@_), ": @_\n "; }
|
|
||||||
if ((!wantarray) && ($num_formals != 0))
|
|
||||||
{ croak "check_args called in scalar context"; }
|
|
||||||
# Can't use croak below here: it would only go out to caller, not its caller
|
|
||||||
my $num_actuals = @args;
|
|
||||||
if ($num_actuals != $num_formals)
|
|
||||||
{ die "$file_arg:$line_arg: function $subname expected $num_formals argument",
|
|
||||||
(($num_formals == 1) ? "" : "s"),
|
|
||||||
", got $num_actuals",
|
|
||||||
(($num_actuals == 0) ? "" : ": @args"),
|
|
||||||
"\n"; }
|
|
||||||
for my $index (0..$#args)
|
|
||||||
{ if (!defined($args[$index]))
|
|
||||||
{ die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } }
|
|
||||||
return @args;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_args_range ( $$@ )
|
|
||||||
{
|
|
||||||
my ($min_formals, $max_formals, @args) = @_;
|
|
||||||
my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1);
|
|
||||||
if (@_ < 2) { croak "check_args_range needs at least 8 args, got ", scalar(@_), ": @_"; }
|
|
||||||
if ((!wantarray) && ($max_formals != 0) && ($min_formals !=0) )
|
|
||||||
{ croak "check_args_range called in scalar context"; }
|
|
||||||
# Can't use croak below here: it would only go out to caller, not its caller
|
|
||||||
my $num_actuals = @args;
|
|
||||||
if (($num_actuals < $min_formals) || ($num_actuals > $max_formals))
|
|
||||||
{ die "$file_arg:$line_arg: function $subname expected $min_formals-$max_formals arguments, got $num_actuals",
|
|
||||||
($num_actuals == 0) ? "" : ": @args", "\n"; }
|
|
||||||
for my $index (0..$#args)
|
|
||||||
{ if (!defined($args[$index]))
|
|
||||||
{ die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } }
|
|
||||||
return @args;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_args_at_least ( $@ )
|
|
||||||
{
|
|
||||||
my ($min_formals, @args) = @_;
|
|
||||||
my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1);
|
|
||||||
# Don't do this, because we want every sub to start with a call to check_args*
|
|
||||||
# if ($min_formals == 0)
|
|
||||||
# { die "Isn't it pointless to check for at least zero args to $subname?\n"; }
|
|
||||||
if (scalar(@_) < 1)
|
|
||||||
{ croak "check_args_at_least needs at least 1 arg, got ", scalar(@_), ": @_"; }
|
|
||||||
if ((!wantarray) && ($min_formals != 0))
|
|
||||||
{ croak "check_args_at_least called in scalar context"; }
|
|
||||||
# Can't use croak below here: it would only go out to caller, not its caller
|
|
||||||
my $num_actuals = @args;
|
|
||||||
if ($num_actuals < $min_formals)
|
|
||||||
{ die "$file_arg:$line_arg: function $subname expected at least $min_formals argument",
|
|
||||||
($min_formals == 1) ? "" : "s",
|
|
||||||
", got $num_actuals",
|
|
||||||
($num_actuals == 0) ? "" : ": @args", "\n"; }
|
|
||||||
for my $index (0..$#args)
|
|
||||||
{ if (!defined($args[$index]))
|
|
||||||
{ warn "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; last; } }
|
|
||||||
return @args;
|
|
||||||
}
|
|
||||||
|
|
||||||
1; # successful import
|
|
||||||
__END__
|
|
@ -1,26 +0,0 @@
|
|||||||
#! /bin/sh
|
|
||||||
# -*- ksh -*-
|
|
||||||
|
|
||||||
# This script *helps* locate lines of normal content that end in '}';
|
|
||||||
# this is useful since LaTeX2HTML (at least the old version that we
|
|
||||||
# use) breaks on many lines that end that way.
|
|
||||||
#
|
|
||||||
# Usage: cklatex files... | less
|
|
||||||
#
|
|
||||||
# *Read* the output looking for suspicious lines!
|
|
||||||
|
|
||||||
grep -n "[^ ]}\$" $@ | \
|
|
||||||
grep -v '\\begin{' | \
|
|
||||||
grep -v '\\end{' | \
|
|
||||||
grep -v '\\input{' | \
|
|
||||||
grep -v '\\documentclass{' | \
|
|
||||||
grep -v '\\title{' | \
|
|
||||||
grep -v '\\chapter{' | \
|
|
||||||
grep -v '\\chapter\*{' | \
|
|
||||||
grep -v '\\section{' | \
|
|
||||||
grep -v '\\subsection{' | \
|
|
||||||
grep -v '\\subsubsection{' | \
|
|
||||||
grep -v '\\sectionauthor{' | \
|
|
||||||
grep -v '\\moduleauthor{'
|
|
||||||
|
|
||||||
exit $?
|
|
@ -1,78 +0,0 @@
|
|||||||
# Generate custlib.tex, which is a site-specific library document.
|
|
||||||
|
|
||||||
# Phase I: list all the things that can be imported
|
|
||||||
|
|
||||||
import glob
|
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
modules = {}
|
|
||||||
|
|
||||||
for modname in sys.builtin_module_names:
|
|
||||||
modules[modname] = modname
|
|
||||||
|
|
||||||
for dir in sys.path:
|
|
||||||
# Look for *.py files
|
|
||||||
filelist = glob.glob(os.path.join(dir, '*.py'))
|
|
||||||
for file in filelist:
|
|
||||||
path, file = os.path.split(file)
|
|
||||||
base, ext = os.path.splitext(file)
|
|
||||||
modules[base.lower()] = base
|
|
||||||
|
|
||||||
# Look for shared library files
|
|
||||||
filelist = (glob.glob(os.path.join(dir, '*.so')) +
|
|
||||||
glob.glob(os.path.join(dir, '*.sl')) +
|
|
||||||
glob.glob(os.path.join(dir, '*.o')) )
|
|
||||||
for file in filelist:
|
|
||||||
path, file = os.path.split(file)
|
|
||||||
base, ext = os.path.splitext(file)
|
|
||||||
if base[-6:] == 'module':
|
|
||||||
base = base[:-6]
|
|
||||||
modules[base.lower()] = base
|
|
||||||
|
|
||||||
# Minor oddity: the types module is documented in libtypes2.tex
|
|
||||||
if modules.has_key('types'):
|
|
||||||
del modules['types']
|
|
||||||
modules['types2'] = None
|
|
||||||
|
|
||||||
# Phase II: find all documentation files (lib*.tex)
|
|
||||||
# and eliminate modules that don't have one.
|
|
||||||
|
|
||||||
docs = {}
|
|
||||||
filelist = glob.glob('lib*.tex')
|
|
||||||
for file in filelist:
|
|
||||||
modname = file[3:-4]
|
|
||||||
docs[modname] = modname
|
|
||||||
|
|
||||||
mlist = modules.keys()
|
|
||||||
mlist = filter(lambda x, docs=docs: docs.has_key(x), mlist)
|
|
||||||
mlist.sort()
|
|
||||||
mlist = map(lambda x, docs=docs: docs[x], mlist)
|
|
||||||
|
|
||||||
modules = mlist
|
|
||||||
|
|
||||||
# Phase III: write custlib.tex
|
|
||||||
|
|
||||||
# Write the boilerplate
|
|
||||||
# XXX should be fancied up.
|
|
||||||
print """\documentstyle[twoside,11pt,myformat]{report}
|
|
||||||
\\title{Python Library Reference}
|
|
||||||
\\input{boilerplate}
|
|
||||||
\\makeindex % tell \\index to actually write the .idx file
|
|
||||||
\\begin{document}
|
|
||||||
\\pagenumbering{roman}
|
|
||||||
\\maketitle
|
|
||||||
\\input{copyright}
|
|
||||||
\\begin{abstract}
|
|
||||||
\\noindent This is a customized version of the Python Library Reference.
|
|
||||||
\\end{abstract}
|
|
||||||
\\pagebreak
|
|
||||||
{\\parskip = 0mm \\tableofcontents}
|
|
||||||
\\pagebreak\\pagenumbering{arabic}"""
|
|
||||||
|
|
||||||
for modname in mlist:
|
|
||||||
print "\\input{lib%s}" % (modname,)
|
|
||||||
|
|
||||||
# Write the end
|
|
||||||
print """\\input{custlib.ind} % Index
|
|
||||||
\\end{document}"""
|
|
@ -1,81 +0,0 @@
|
|||||||
"""Utility class and function to get information about the CVS repository
|
|
||||||
based on checked-out files.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def get_repository_list(paths):
|
|
||||||
d = {}
|
|
||||||
for name in paths:
|
|
||||||
if os.path.isfile(name):
|
|
||||||
dir = os.path.dirname(name)
|
|
||||||
else:
|
|
||||||
dir = name
|
|
||||||
rootfile = os.path.join(name, "CVS", "Root")
|
|
||||||
root = open(rootfile).readline().strip()
|
|
||||||
if not d.has_key(root):
|
|
||||||
d[root] = RepositoryInfo(dir), [name]
|
|
||||||
else:
|
|
||||||
d[root][1].append(name)
|
|
||||||
return d.values()
|
|
||||||
|
|
||||||
|
|
||||||
class RepositoryInfo:
|
|
||||||
"""Record holding information about the repository we want to talk to."""
|
|
||||||
cvsroot_path = None
|
|
||||||
branch = None
|
|
||||||
|
|
||||||
# type is '', ':ext', or ':pserver:'
|
|
||||||
type = ""
|
|
||||||
|
|
||||||
def __init__(self, dir=None):
|
|
||||||
if dir is None:
|
|
||||||
dir = os.getcwd()
|
|
||||||
dir = os.path.join(dir, "CVS")
|
|
||||||
root = open(os.path.join(dir, "Root")).readline().strip()
|
|
||||||
if root.startswith(":pserver:"):
|
|
||||||
self.type = ":pserver:"
|
|
||||||
root = root[len(":pserver:"):]
|
|
||||||
elif ":" in root:
|
|
||||||
if root.startswith(":ext:"):
|
|
||||||
root = root[len(":ext:"):]
|
|
||||||
self.type = ":ext:"
|
|
||||||
self.repository = root
|
|
||||||
if ":" in root:
|
|
||||||
host, path = root.split(":", 1)
|
|
||||||
self.cvsroot_path = path
|
|
||||||
else:
|
|
||||||
self.cvsroot_path = root
|
|
||||||
fn = os.path.join(dir, "Tag")
|
|
||||||
if os.path.isfile(fn):
|
|
||||||
self.branch = open(fn).readline().strip()[1:]
|
|
||||||
|
|
||||||
def get_cvsroot(self):
|
|
||||||
return self.type + self.repository
|
|
||||||
|
|
||||||
_repository_dir_cache = {}
|
|
||||||
|
|
||||||
def get_repository_file(self, path):
|
|
||||||
filename = os.path.abspath(path)
|
|
||||||
if os.path.isdir(path):
|
|
||||||
dir = path
|
|
||||||
join = 0
|
|
||||||
else:
|
|
||||||
dir = os.path.dirname(path)
|
|
||||||
join = 1
|
|
||||||
try:
|
|
||||||
repodir = self._repository_dir_cache[dir]
|
|
||||||
except KeyError:
|
|
||||||
repofn = os.path.join(dir, "CVS", "Repository")
|
|
||||||
repodir = open(repofn).readline().strip()
|
|
||||||
repodir = os.path.join(self.cvsroot_path, repodir)
|
|
||||||
self._repository_dir_cache[dir] = repodir
|
|
||||||
if join:
|
|
||||||
fn = os.path.join(repodir, os.path.basename(path))
|
|
||||||
else:
|
|
||||||
fn = repodir
|
|
||||||
return fn[len(self.cvsroot_path)+1:]
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<RepositoryInfo for %s>" % `self.get_cvsroot()`
|
|
@ -1,161 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""Script to locate email addresses in the CVS logs."""
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import UserDict
|
|
||||||
|
|
||||||
import cvsinfo
|
|
||||||
|
|
||||||
|
|
||||||
class Acknowledgements(UserDict.UserDict):
|
|
||||||
def add(self, email, name, path):
|
|
||||||
d = self.data
|
|
||||||
d.setdefault(email, {})[path] = name
|
|
||||||
|
|
||||||
|
|
||||||
def open_cvs_log(info, paths=None):
|
|
||||||
cvsroot = info.get_cvsroot()
|
|
||||||
cmd = "cvs -q -d%s log " % cvsroot
|
|
||||||
if paths:
|
|
||||||
cmd += " ".join(paths)
|
|
||||||
return os.popen(cmd, "r")
|
|
||||||
|
|
||||||
|
|
||||||
email_rx = re.compile("<([a-z][-a-z0-9._]*@[-a-z0-9.]+)>", re.IGNORECASE)
|
|
||||||
|
|
||||||
def find_acks(f, acks):
|
|
||||||
prev = ''
|
|
||||||
filename = None
|
|
||||||
MAGIC_WORDS = ('van', 'von')
|
|
||||||
while 1:
|
|
||||||
line = f.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
if line.startswith("Working file: "):
|
|
||||||
filename = line.split(None, 2)[2].strip()
|
|
||||||
prev = line
|
|
||||||
continue
|
|
||||||
m = email_rx.search(line)
|
|
||||||
if m:
|
|
||||||
words = prev.split() + line[:m.start()].split()
|
|
||||||
L = []
|
|
||||||
while words \
|
|
||||||
and (words[-1][0].isupper() or words[-1] in MAGIC_WORDS):
|
|
||||||
L.insert(0, words.pop())
|
|
||||||
name = " ".join(L)
|
|
||||||
email = m.group(1).lower()
|
|
||||||
acks.add(email, name, filename)
|
|
||||||
prev = line
|
|
||||||
|
|
||||||
|
|
||||||
def load_cvs_log_acks(acks, args):
|
|
||||||
repolist = cvsinfo.get_repository_list(args or [""])
|
|
||||||
for info, paths in repolist:
|
|
||||||
print >>sys.stderr, "Repository:", info.get_cvsroot()
|
|
||||||
f = open_cvs_log(info, paths)
|
|
||||||
find_acks(f, acks)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
|
|
||||||
def load_tex_source_acks(acks, args):
|
|
||||||
for path in args:
|
|
||||||
path = path or os.curdir
|
|
||||||
if os.path.isfile(path):
|
|
||||||
read_acks_from_tex_file(acks, path)
|
|
||||||
else:
|
|
||||||
read_acks_from_tex_dir(acks, path)
|
|
||||||
|
|
||||||
|
|
||||||
def read_acks_from_tex_file(acks, path):
|
|
||||||
f = open(path)
|
|
||||||
while 1:
|
|
||||||
line = f.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
if line.startswith(r"\sectionauthor{"):
|
|
||||||
line = line[len(r"\sectionauthor"):]
|
|
||||||
name, line = extract_tex_group(line)
|
|
||||||
email, line = extract_tex_group(line)
|
|
||||||
acks.add(email, name, path)
|
|
||||||
|
|
||||||
|
|
||||||
def read_acks_from_tex_dir(acks, path):
|
|
||||||
stack = [path]
|
|
||||||
while stack:
|
|
||||||
p = stack.pop()
|
|
||||||
for n in os.listdir(p):
|
|
||||||
n = os.path.join(p, n)
|
|
||||||
if os.path.isdir(n):
|
|
||||||
stack.insert(0, n)
|
|
||||||
elif os.path.normpath(n).endswith(".tex"):
|
|
||||||
read_acks_from_tex_file(acks, n)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_tex_group(s):
|
|
||||||
c = 0
|
|
||||||
for i in range(len(s)):
|
|
||||||
if s[i] == '{':
|
|
||||||
c += 1
|
|
||||||
elif s[i] == '}':
|
|
||||||
c -= 1
|
|
||||||
if c == 0:
|
|
||||||
return s[1:i], s[i+1:]
|
|
||||||
|
|
||||||
|
|
||||||
def print_acks(acks):
|
|
||||||
first = 1
|
|
||||||
for email, D in acks.items():
|
|
||||||
if first:
|
|
||||||
first = 0
|
|
||||||
else:
|
|
||||||
print
|
|
||||||
L = D.items()
|
|
||||||
L.sort()
|
|
||||||
prefname = L[0][1]
|
|
||||||
for file, name in L[1:]:
|
|
||||||
if name != prefname:
|
|
||||||
prefname = ""
|
|
||||||
break
|
|
||||||
if prefname:
|
|
||||||
print prefname, "<%s>:" % email
|
|
||||||
else:
|
|
||||||
print email + ":"
|
|
||||||
for file, name in L:
|
|
||||||
if name == prefname:
|
|
||||||
print " " + file
|
|
||||||
else:
|
|
||||||
print " %s (as %s)" % (file, name)
|
|
||||||
|
|
||||||
|
|
||||||
def print_ack_names(acks):
|
|
||||||
names = []
|
|
||||||
for email, D in acks.items():
|
|
||||||
L = D.items()
|
|
||||||
L.sort()
|
|
||||||
prefname = L[0][1]
|
|
||||||
for file, name in L[1:]:
|
|
||||||
prefname = prefname or name
|
|
||||||
names.append(prefname or email)
|
|
||||||
def f(s1, s2):
|
|
||||||
s1 = s1.lower()
|
|
||||||
s2 = s2.lower()
|
|
||||||
return cmp((s1.split()[-1], s1),
|
|
||||||
(s2.split()[-1], s2))
|
|
||||||
names.sort(f)
|
|
||||||
for name in names:
|
|
||||||
print name
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = sys.argv[1:]
|
|
||||||
acks = Acknowledgements()
|
|
||||||
load_cvs_log_acks(acks, args)
|
|
||||||
load_tex_source_acks(acks, args)
|
|
||||||
print_ack_names(acks)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,136 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
import errno
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
_base = sys.argv[0]
|
|
||||||
else:
|
|
||||||
_base = __file__
|
|
||||||
|
|
||||||
_script_home = os.path.abspath(os.path.dirname(_base))
|
|
||||||
|
|
||||||
srcdir = os.path.dirname(os.path.dirname(_script_home))
|
|
||||||
|
|
||||||
EXCLUDES = ["bitset.h", "cStringIO.h", "graminit.h", "grammar.h",
|
|
||||||
"longintrepr.h", "metagrammar.h",
|
|
||||||
"node.h", "opcode.h", "osdefs.h", "pgenheaders.h",
|
|
||||||
"py_curses.h", "parsetok.h", "symtable.h", "token.h"]
|
|
||||||
|
|
||||||
|
|
||||||
def list_headers():
|
|
||||||
"""Return a list of headers."""
|
|
||||||
incdir = os.path.join(srcdir, "Include")
|
|
||||||
return [fn for fn in os.listdir(incdir)
|
|
||||||
if fn.endswith(".h") and fn not in EXCLUDES]
|
|
||||||
|
|
||||||
|
|
||||||
def matcher(pattern):
|
|
||||||
return re.compile(pattern).match
|
|
||||||
|
|
||||||
MATCHERS = [
|
|
||||||
matcher(r"\\begin\{cfuncdesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\cfuncline\{[^{]*\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\begin\{ctypedesc\}(\[[^{]*\])?\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\begin\{cvardesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\begin\{cmemberdesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\cmemberline\{[^{]*\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
matcher(r"\\begin\{csimplemacrodesc\}\{(?P<sym>[^{]*)\}"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def list_documented_items():
|
|
||||||
"""Return a list of everything that's already documented."""
|
|
||||||
apidir = os.path.join(srcdir, "Doc", "api")
|
|
||||||
files = [fn for fn in os.listdir(apidir) if fn.endswith(".tex")]
|
|
||||||
L = []
|
|
||||||
for fn in files:
|
|
||||||
fullname = os.path.join(apidir, fn)
|
|
||||||
for line in open(fullname):
|
|
||||||
line = line.lstrip()
|
|
||||||
if not line.startswith("\\"):
|
|
||||||
continue
|
|
||||||
for matcher in MATCHERS:
|
|
||||||
m = matcher(line)
|
|
||||||
if m:
|
|
||||||
L.append(m.group("sym"))
|
|
||||||
break
|
|
||||||
return L
|
|
||||||
|
|
||||||
def split_documented(all, documented):
|
|
||||||
"""Split the list of all symbols into documented and undocumented
|
|
||||||
categories."""
|
|
||||||
doc = []
|
|
||||||
undoc = []
|
|
||||||
for t in all:
|
|
||||||
if t[0] in documented:
|
|
||||||
doc.append(t)
|
|
||||||
else:
|
|
||||||
undoc.append(t)
|
|
||||||
return doc, undoc
|
|
||||||
|
|
||||||
def print_list(L, title=None):
|
|
||||||
"""Dump a list to stdout."""
|
|
||||||
if title:
|
|
||||||
print title + ":"
|
|
||||||
print "-" * (len(title) + 1)
|
|
||||||
w = 0
|
|
||||||
for sym, filename in L:
|
|
||||||
w = max(w, len(sym))
|
|
||||||
if w % 4 == 0:
|
|
||||||
w += 4
|
|
||||||
else:
|
|
||||||
w += (4 - (w % 4))
|
|
||||||
for sym, filename in L:
|
|
||||||
print "%-*s%s" % (w, sym, filename)
|
|
||||||
|
|
||||||
|
|
||||||
_spcjoin = ' '.join
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = sys.argv[1:]
|
|
||||||
if args:
|
|
||||||
headers = args
|
|
||||||
documented = []
|
|
||||||
else:
|
|
||||||
os.chdir(os.path.join(srcdir, "Include"))
|
|
||||||
headers = list_headers()
|
|
||||||
documented = list_documented_items()
|
|
||||||
|
|
||||||
cmd = ("ctags -f - --file-scope=no --c-types=dgpstux "
|
|
||||||
"-Istaticforward -Istatichere=static "
|
|
||||||
+ _spcjoin(headers))
|
|
||||||
fp = os.popen(cmd)
|
|
||||||
L = []
|
|
||||||
prevsym = None
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
sym, filename = line.split()[:2]
|
|
||||||
if sym == prevsym:
|
|
||||||
continue
|
|
||||||
if not sym.endswith("_H"):
|
|
||||||
L.append((sym, filename))
|
|
||||||
prevsym = sym
|
|
||||||
L.sort()
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if documented:
|
|
||||||
documented, undocumented = split_documented(L, documented)
|
|
||||||
print_list(documented, "Documented symbols")
|
|
||||||
if undocumented:
|
|
||||||
print
|
|
||||||
print_list(undocumented, "Undocumented symbols")
|
|
||||||
else:
|
|
||||||
print_list(L)
|
|
||||||
except IOError, e:
|
|
||||||
if e.errno != errno.EPIPE:
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,63 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
|
|
||||||
import fileinput
|
|
||||||
import getopt
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
declare_rx = re.compile(
|
|
||||||
r"\\declaremodule(?:\[[a-zA-Z0-9]*\]*)?{[a-zA-Z_0-9]+}{([a-zA-Z_0-9]+)}")
|
|
||||||
|
|
||||||
module_rx = re.compile(r"\\module{([a-zA-Z_0-9]+)}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
just_list = 0
|
|
||||||
print_lineno = 0
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "ln", ["list", "number"])
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ("-l", "--list"):
|
|
||||||
just_list = 1
|
|
||||||
elif opt in ("-n", "--number"):
|
|
||||||
print_lineno = 1
|
|
||||||
files = args
|
|
||||||
if not files:
|
|
||||||
files = glob.glob("*.tex")
|
|
||||||
files.sort()
|
|
||||||
modulename = None
|
|
||||||
for line in fileinput.input(files):
|
|
||||||
if line[:9] == r"\section{":
|
|
||||||
modulename = None
|
|
||||||
continue
|
|
||||||
if line[:16] == r"\modulesynopsys{":
|
|
||||||
continue
|
|
||||||
m = declare_rx.match(line)
|
|
||||||
if m:
|
|
||||||
modulename = m.group(1)
|
|
||||||
continue
|
|
||||||
if not modulename:
|
|
||||||
continue
|
|
||||||
m = module_rx.search(line)
|
|
||||||
if m:
|
|
||||||
name = m.group(1)
|
|
||||||
if name != modulename:
|
|
||||||
filename = fileinput.filename()
|
|
||||||
if just_list:
|
|
||||||
print filename
|
|
||||||
fileinput.nextfile()
|
|
||||||
modulename = None
|
|
||||||
elif print_lineno:
|
|
||||||
print "%s(%d):%s" \
|
|
||||||
% (filename, fileinput.filelineno(), line[:-1])
|
|
||||||
else:
|
|
||||||
print "%s:%s" % (filename, line[:-1])
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,128 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Released to the public domain by Skip Montanaro, 28 March 2002
|
|
||||||
|
|
||||||
"""
|
|
||||||
findsyms.py - try to identify undocumented symbols exported by modules
|
|
||||||
|
|
||||||
Usage: findsyms.py librefdir
|
|
||||||
|
|
||||||
For each lib*.tex file in the libref manual source directory, identify which
|
|
||||||
module is documented, import the module if possible, then search the LaTeX
|
|
||||||
source for the symbols global to that module. Report any that don't seem to
|
|
||||||
be documented.
|
|
||||||
|
|
||||||
Certain exceptions are made to the list of undocumented symbols:
|
|
||||||
|
|
||||||
* don't mention symbols in which all letters are upper case on the
|
|
||||||
assumption they are manifest constants
|
|
||||||
|
|
||||||
* don't mention symbols that are themselves modules
|
|
||||||
|
|
||||||
* don't mention symbols that match those exported by os, math, string,
|
|
||||||
types, or __builtin__ modules
|
|
||||||
|
|
||||||
Finally, if a name is exported by the module but fails a getattr() lookup,
|
|
||||||
that anomaly is reported.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import __builtin__
|
|
||||||
import getopt
|
|
||||||
import glob
|
|
||||||
import math
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import string
|
|
||||||
import sys
|
|
||||||
import types
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
print >> sys.stderr, """
|
|
||||||
usage: %s dir
|
|
||||||
where 'dir' is the Library Reference Manual source directory.
|
|
||||||
""" % os.path.basename(sys.argv[0])
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "")
|
|
||||||
except getopt.error:
|
|
||||||
usage()
|
|
||||||
return
|
|
||||||
|
|
||||||
if not args:
|
|
||||||
usage()
|
|
||||||
return
|
|
||||||
|
|
||||||
libdir = args[0]
|
|
||||||
|
|
||||||
warnings.filterwarnings("error")
|
|
||||||
|
|
||||||
pat = re.compile(r"\\declaremodule\s*{[^}]*}\s*{([^}]*)}")
|
|
||||||
|
|
||||||
missing = []
|
|
||||||
filelist = glob.glob(os.path.join(libdir, "lib*.tex"))
|
|
||||||
filelist.sort()
|
|
||||||
for f in filelist:
|
|
||||||
mod = f[3:-4]
|
|
||||||
if not mod: continue
|
|
||||||
data = open(f).read()
|
|
||||||
mods = re.findall(pat, data)
|
|
||||||
if not mods:
|
|
||||||
print "No module declarations found in", f
|
|
||||||
continue
|
|
||||||
for modname in mods:
|
|
||||||
# skip special modules
|
|
||||||
if modname.startswith("__"):
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
mod = __import__(modname)
|
|
||||||
except ImportError:
|
|
||||||
missing.append(modname)
|
|
||||||
continue
|
|
||||||
except DeprecationWarning:
|
|
||||||
print "Deprecated module:", modname
|
|
||||||
continue
|
|
||||||
if hasattr(mod, "__all__"):
|
|
||||||
all = mod.__all__
|
|
||||||
else:
|
|
||||||
all = [k for k in dir(mod) if k[0] != "_"]
|
|
||||||
mentioned = 0
|
|
||||||
all.sort()
|
|
||||||
for name in all:
|
|
||||||
if data.find(name) == -1:
|
|
||||||
# certain names are predominantly used for testing
|
|
||||||
if name in ("main","test","_test"):
|
|
||||||
continue
|
|
||||||
# is it some sort of manifest constant?
|
|
||||||
if name.upper() == name:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
item = getattr(mod, name)
|
|
||||||
except AttributeError:
|
|
||||||
print " ", name, "exposed, but not an attribute"
|
|
||||||
continue
|
|
||||||
# don't care about modules that might be exposed
|
|
||||||
if type(item) == types.ModuleType:
|
|
||||||
continue
|
|
||||||
# check a few modules which tend to be import *'d
|
|
||||||
isglobal = 0
|
|
||||||
for m in (os, math, string, __builtin__, types):
|
|
||||||
if hasattr(m, name) and item == getattr(m, name):
|
|
||||||
isglobal = 1
|
|
||||||
break
|
|
||||||
if isglobal: continue
|
|
||||||
if not mentioned:
|
|
||||||
print "Not mentioned in", modname, "docs:"
|
|
||||||
mentioned = 1
|
|
||||||
print " ", name
|
|
||||||
if missing:
|
|
||||||
missing.sort()
|
|
||||||
print "Could not import:"
|
|
||||||
print " ", ", ".join(missing)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
main()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
sed -e 's/{\\ptt[ ]*\\char[ ]*'"'"'137}/_/g' <"$1" > "@$1" && mv "@$1" $1
|
|
@ -1,3 +0,0 @@
|
|||||||
#! /bin/sed -f
|
|
||||||
s/{\\tt \\hackscore {}\\hackscore {}/\\sectcode{__/
|
|
||||||
s/\\hackscore {}\\hackscore {}/__/
|
|
@ -1,15 +0,0 @@
|
|||||||
(defun fix-python-texinfo ()
|
|
||||||
(goto-char (point-min))
|
|
||||||
(replace-regexp "\\(@setfilename \\)\\([-a-z]*\\)$"
|
|
||||||
"\\1python-\\2.info")
|
|
||||||
(replace-string "@node Front Matter\n@chapter Abstract\n"
|
|
||||||
"@node Abstract\n@section Abstract\n")
|
|
||||||
(mark-whole-buffer)
|
|
||||||
(texinfo-master-menu 'update-all-nodes)
|
|
||||||
(save-buffer)
|
|
||||||
) ;; fix-python-texinfo
|
|
||||||
|
|
||||||
;; now really do it:
|
|
||||||
(find-file (car command-line-args-left))
|
|
||||||
(fix-python-texinfo)
|
|
||||||
(kill-emacs)
|
|
@ -1,97 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
"""Generate a page count report of the PostScript version of the manuals."""
|
|
||||||
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
class PageCounter:
|
|
||||||
def __init__(self):
|
|
||||||
self.doclist = []
|
|
||||||
self.total = 0
|
|
||||||
self.title_width = 0
|
|
||||||
self.version = ""
|
|
||||||
|
|
||||||
def add_document(self, prefix, title):
|
|
||||||
count = count_pages(prefix + ".ps")
|
|
||||||
self.doclist.append((title, prefix, count))
|
|
||||||
self.title_width = max(self.title_width, len(title))
|
|
||||||
self.total = self.total + count
|
|
||||||
|
|
||||||
def dump(self):
|
|
||||||
fmt = "%%-%ds (%%s.ps, %%d pages)" % self.title_width
|
|
||||||
for item in self.doclist:
|
|
||||||
print fmt % item
|
|
||||||
print
|
|
||||||
print " Total page count: %d" % self.total
|
|
||||||
|
|
||||||
def parse_options(self):
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "r:", ["release="])
|
|
||||||
assert not args
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ("-r", "--release"):
|
|
||||||
self.version = arg
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.parse_options()
|
|
||||||
if self.version:
|
|
||||||
version = self.version[:3]
|
|
||||||
self.add_document("whatsnew" + version.replace(".", ""),
|
|
||||||
"What's New in Python " + version)
|
|
||||||
for prefix, title in [
|
|
||||||
("api", "Python/C API"),
|
|
||||||
("ext", "Extending and Embedding the Python Interpreter"),
|
|
||||||
("lib", "Python Library Reference"),
|
|
||||||
("mac", "Macintosh Module Reference"),
|
|
||||||
("ref", "Python Reference Manual"),
|
|
||||||
("tut", "Python Tutorial"),
|
|
||||||
("doc", "Documenting Python"),
|
|
||||||
("inst", "Installing Python Modules"),
|
|
||||||
("dist", "Distributing Python Modules"),
|
|
||||||
]:
|
|
||||||
self.add_document(prefix, title)
|
|
||||||
print self.PREFIX
|
|
||||||
self.dump()
|
|
||||||
print self.SUFFIX
|
|
||||||
|
|
||||||
PREFIX = """\
|
|
||||||
This is the PostScript version of the standard Python documentation.
|
|
||||||
If you plan to print this, be aware that some of the documents are
|
|
||||||
long. It is formatted for printing on two-sided paper; if you do plan
|
|
||||||
to print this, *please* print two-sided if you have a printer capable
|
|
||||||
of it! To locate published copies of the larger manuals, or other
|
|
||||||
Python reference material, consult the Python Bookstore at:
|
|
||||||
|
|
||||||
http://www.amk.ca/bookstore/
|
|
||||||
|
|
||||||
The following manuals are included in this package:
|
|
||||||
"""
|
|
||||||
SUFFIX = """\
|
|
||||||
|
|
||||||
|
|
||||||
If you have any questions, comments, or suggestions regarding these
|
|
||||||
documents, please send them via email to python-docs@python.org.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def count_pages(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
count = 0
|
|
||||||
while 1:
|
|
||||||
lines = fp.readlines(1024*40)
|
|
||||||
if not lines:
|
|
||||||
break
|
|
||||||
for line in lines:
|
|
||||||
if line[:7] == "%%Page:":
|
|
||||||
count = count + 1
|
|
||||||
fp.close()
|
|
||||||
return count
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
PageCounter().run()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,100 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
"""Combine similar index entries into an entry and subentries.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
\item {foobar} (in module flotz), 23
|
|
||||||
\item {foobar} (in module whackit), 4323
|
|
||||||
|
|
||||||
becomes
|
|
||||||
|
|
||||||
\item {foobar}
|
|
||||||
\subitem in module flotz, 23
|
|
||||||
\subitem in module whackit, 4323
|
|
||||||
|
|
||||||
Note that an item which matches the format of a collapsable item but which
|
|
||||||
isn't part of a group of similar items is not modified.
|
|
||||||
"""
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import re
|
|
||||||
import StringIO
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def cmp_entries(e1, e2):
|
|
||||||
return cmp(e1[1].lower(), e2[1].lower()) or cmp(e1, e2)
|
|
||||||
|
|
||||||
|
|
||||||
def dump_entries(write, entries):
|
|
||||||
if len(entries) == 1:
|
|
||||||
write(" \\item %s (%s)%s\n" % entries[0])
|
|
||||||
return
|
|
||||||
write(" \item %s\n" % entries[0][0])
|
|
||||||
# now sort these in a case insensitive manner:
|
|
||||||
if len(entries) > 0:
|
|
||||||
entries.sort(cmp_entries)
|
|
||||||
for xxx, subitem, pages in entries:
|
|
||||||
write(" \subitem %s%s\n" % (subitem, pages))
|
|
||||||
|
|
||||||
|
|
||||||
breakable_re = re.compile(
|
|
||||||
r" \\item (.*) [(](.*)[)]((?:(?:, \d+)|(?:, \\[a-z]*\{\d+\}))+)")
|
|
||||||
|
|
||||||
|
|
||||||
def process(ifn, ofn=None):
|
|
||||||
if ifn == "-":
|
|
||||||
ifp = sys.stdin
|
|
||||||
else:
|
|
||||||
ifp = open(ifn)
|
|
||||||
if ofn is None:
|
|
||||||
ofn = ifn
|
|
||||||
ofp = StringIO.StringIO()
|
|
||||||
entries = []
|
|
||||||
match = breakable_re.match
|
|
||||||
write = ofp.write
|
|
||||||
while 1:
|
|
||||||
line = ifp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
m = match(line)
|
|
||||||
if m:
|
|
||||||
entry = m.group(1, 2, 3)
|
|
||||||
if entries and entries[-1][0] != entry[0]:
|
|
||||||
dump_entries(write, entries)
|
|
||||||
entries = []
|
|
||||||
entries.append(entry)
|
|
||||||
elif entries:
|
|
||||||
dump_entries(write, entries)
|
|
||||||
entries = []
|
|
||||||
write(line)
|
|
||||||
else:
|
|
||||||
write(line)
|
|
||||||
del write
|
|
||||||
del match
|
|
||||||
ifp.close()
|
|
||||||
data = ofp.getvalue()
|
|
||||||
ofp.close()
|
|
||||||
if ofn == "-":
|
|
||||||
ofp = sys.stdout
|
|
||||||
else:
|
|
||||||
ofp = open(ofn, "w")
|
|
||||||
ofp.write(data)
|
|
||||||
ofp.close()
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import getopt
|
|
||||||
outfile = None
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "o:")
|
|
||||||
for opt, val in opts:
|
|
||||||
if opt in ("-o", "--output"):
|
|
||||||
outfile = val
|
|
||||||
filename = args[0]
|
|
||||||
outfile = outfile or filename
|
|
||||||
process(filename, outfile)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,19 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
# This Python program sorts and reformats the table of keywords in ref2.tex
|
|
||||||
|
|
||||||
l = []
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
l = l + raw_input().split()
|
|
||||||
except EOFError:
|
|
||||||
pass
|
|
||||||
l.sort()
|
|
||||||
for x in l[:]:
|
|
||||||
while l.count(x) > 1: l.remove(x)
|
|
||||||
ncols = 5
|
|
||||||
nrows = (len(l)+ncols-1)/ncols
|
|
||||||
for i in range(nrows):
|
|
||||||
for j in range(i, len(l), nrows):
|
|
||||||
print l[j].ljust(10),
|
|
||||||
print
|
|
@ -1,183 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
#
|
|
||||||
# This script can be used to identify undocumented modules in the Python
|
|
||||||
# standard library. Use it like this:
|
|
||||||
#
|
|
||||||
# .../Doc/tools/listmodules --ignore-from .../Doc/paper-<paper>/modlib.idx
|
|
||||||
|
|
||||||
"""%(program)s - list modules in the Python standard library
|
|
||||||
|
|
||||||
-a, --annotate Annotate the module names with the subdirectory they
|
|
||||||
live in
|
|
||||||
-c, --categorize Group the modules by subdirectory
|
|
||||||
-i <file>,
|
|
||||||
|
|
||||||
--ignore-from <file> Ignore the modules listed in <file>. <file> may
|
|
||||||
contain a list of module names or a module index file
|
|
||||||
as produced when formatting the Python documentation
|
|
||||||
(.idx or .html flavor).
|
|
||||||
|
|
||||||
If neither -a nor -c are given, the modules are listed in alphabetical
|
|
||||||
order.
|
|
||||||
|
|
||||||
Note that -a and -c are mutually exclusive.
|
|
||||||
|
|
||||||
Limitation: Modules loadable as shared objects may not be listed,
|
|
||||||
though this script attempts to locate such modules.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import string
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
REMOVE_DIRS = ["dos-8x3", "encodings", "distutils",
|
|
||||||
"lib-old", "lib-stdwin", "test"]
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = sys.argv[1:]
|
|
||||||
annotate = 0
|
|
||||||
builtin = 0
|
|
||||||
categorize = 0
|
|
||||||
ignore_dict = {}
|
|
||||||
ignore = ignore_dict.has_key
|
|
||||||
try:
|
|
||||||
opts, args = getopt.getopt(
|
|
||||||
args, "abchi:",
|
|
||||||
["annotate", "built-in", "categorize", "help", "ignore-from="])
|
|
||||||
except getopt.error, msg:
|
|
||||||
sys.stdout = sys.stderr
|
|
||||||
print msg
|
|
||||||
print
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ("-a", "--annotate"):
|
|
||||||
annotate = 1
|
|
||||||
elif opt in ("-b", "--built-in"):
|
|
||||||
builtin = 1
|
|
||||||
elif opt in ("-c", "--categorize"):
|
|
||||||
categorize = 1
|
|
||||||
elif opt in ("-h", "--help"):
|
|
||||||
usage()
|
|
||||||
sys.exit()
|
|
||||||
elif opt in ("-i", "--ignore-from"):
|
|
||||||
data = open(arg).read()
|
|
||||||
if data[:1] == "\\":
|
|
||||||
ignore_from_idx(data, ignore_dict)
|
|
||||||
else:
|
|
||||||
ignore_from_modulelist(data, ignore_dict)
|
|
||||||
if args or (annotate and categorize):
|
|
||||||
usage()
|
|
||||||
sys.exit(2)
|
|
||||||
#
|
|
||||||
# Populate the database:
|
|
||||||
#
|
|
||||||
srcdir = os.path.normpath(os.path.join(
|
|
||||||
os.path.dirname(sys.argv[0]), os.pardir, os.pardir))
|
|
||||||
os.chdir(srcdir)
|
|
||||||
modules_by_name = {}
|
|
||||||
modules_by_dir = {}
|
|
||||||
if builtin:
|
|
||||||
l = []
|
|
||||||
modules_by_dir["<builtin>"] = l
|
|
||||||
for name in sys.builtin_module_names:
|
|
||||||
if not ignore(name):
|
|
||||||
modules_by_name[name] = "<built-in>"
|
|
||||||
l.append(name)
|
|
||||||
rx = re.compile("Lib/plat-[a-zA-Z0-9]*/")
|
|
||||||
fp = os.popen("find Lib -name \*.py -print", "r")
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
m = rx.match(line)
|
|
||||||
if m:
|
|
||||||
line = "Lib/plat-*/" + line[m.end():]
|
|
||||||
line = line[4:-4] # strip off 'Lib/' and '.py\n'
|
|
||||||
dir, name = os.path.split(line)
|
|
||||||
dir = dir or "<standard>"
|
|
||||||
if ignore(name):
|
|
||||||
continue
|
|
||||||
if dir not in REMOVE_DIRS:
|
|
||||||
modules_by_name[name] = dir
|
|
||||||
l = modules_by_dir.get(dir, [])
|
|
||||||
modules_by_dir[dir] = l
|
|
||||||
if name not in l:
|
|
||||||
l.append(name)
|
|
||||||
# load up extension modules:
|
|
||||||
pwd = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir("Modules")
|
|
||||||
dir = "<extension>"
|
|
||||||
for line in glob.glob("*module.c"):
|
|
||||||
name = line[:-8]
|
|
||||||
if ignore(name) or modules_by_name.has_key(name) or name == "xx":
|
|
||||||
continue
|
|
||||||
modules_by_name[name] = dir
|
|
||||||
l = modules_by_dir.get(dir, [])
|
|
||||||
modules_by_dir[dir] = l
|
|
||||||
if name not in l:
|
|
||||||
l.append(name)
|
|
||||||
finally:
|
|
||||||
os.chdir(pwd)
|
|
||||||
#
|
|
||||||
# Dump the results:
|
|
||||||
#
|
|
||||||
if annotate:
|
|
||||||
modules = modules_by_name.items()
|
|
||||||
modules.sort()
|
|
||||||
width = max(map(len, modules_by_name.keys()))
|
|
||||||
format = "%%-%ds %%s" % width
|
|
||||||
for name, dir in modules:
|
|
||||||
if dir and dir[0] != "<":
|
|
||||||
print format % (name, dir)
|
|
||||||
else:
|
|
||||||
print name
|
|
||||||
elif categorize:
|
|
||||||
modules = modules_by_dir.items()
|
|
||||||
modules.sort()
|
|
||||||
width = max(map(len, modules_by_dir.keys()))
|
|
||||||
format = "%%-%ds %%s" % width
|
|
||||||
for dir, names in modules:
|
|
||||||
names.sort()
|
|
||||||
print format % (dir, names[0])
|
|
||||||
for name in names[1:]:
|
|
||||||
print format % ('', name)
|
|
||||||
print
|
|
||||||
else:
|
|
||||||
modules = modules_by_name.keys()
|
|
||||||
modules.sort()
|
|
||||||
print string.join(modules, "\n")
|
|
||||||
|
|
||||||
|
|
||||||
def ignore_from_modulelist(data, ignore_dict):
|
|
||||||
for name in string.split(data):
|
|
||||||
ignore_dict[name] = name
|
|
||||||
|
|
||||||
def ignore_from_idx(data, ignore_dict):
|
|
||||||
data = string.replace(data, r"\hackscore {}", "_")
|
|
||||||
rx = re.compile(r"\\indexentry\s*{([^@]*)@")
|
|
||||||
for line in string.split(data, "\n"):
|
|
||||||
m = rx.match(line)
|
|
||||||
if m:
|
|
||||||
name = m.group(1)
|
|
||||||
ignore_dict[name] = name
|
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
vars = {}
|
|
||||||
vars["program"] = os.path.basename(sys.argv[0])
|
|
||||||
print __doc__ % vars
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,129 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Simple little checker for individual libref manual sections
|
|
||||||
#
|
|
||||||
# usage: makesec.sh section
|
|
||||||
#
|
|
||||||
|
|
||||||
# This script builds the minimal file necessary to run a single section
|
|
||||||
# through latex, does so, then converts the resulting dvi file to ps or pdf
|
|
||||||
# and feeds the result into a viewer. It's by no means foolproof, but seems
|
|
||||||
# to work okay for me (knock wood). It sure beats manually commenting out
|
|
||||||
# most of the man lib.tex file and running everything manually.
|
|
||||||
|
|
||||||
# It attempts to locate an appropriate dvi converter and viewer for the
|
|
||||||
# selected output format. It understands the following environment
|
|
||||||
# variables:
|
|
||||||
#
|
|
||||||
# PYSRC - refers to the root of your build tree (dir containing Doc)
|
|
||||||
# DVICVT - refers to a dvi converter like dvips or dvipdf
|
|
||||||
# VIEWER - refers to an appropriate viewer for the ps/pdf file
|
|
||||||
#
|
|
||||||
# Of the three, only PYSRC is currently required. The other two can be set
|
|
||||||
# to specify unusual tools which perform those tasks.
|
|
||||||
|
|
||||||
# Known issues:
|
|
||||||
# - It would be nice if the script could determine PYSRC on its own.
|
|
||||||
# - Something about \seealso{}s blows the latex stack, so they need
|
|
||||||
# to be commented out for now.
|
|
||||||
|
|
||||||
if [ x$PYSRC = x ] ; then
|
|
||||||
echo "PYSRC must refer to the Python source tree" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d $PYSRC/Doc ] ; then
|
|
||||||
echo "Can't find a Doc subdirectory in $PYSRC" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$#" -ne 1 ] ; then
|
|
||||||
echo "Must specify a single libref manual section on cmd line" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# settle on a dvi converter
|
|
||||||
if [ x$DVICVT != x ] ; then
|
|
||||||
converter=$DVICVT
|
|
||||||
ext=`echo $DVICVT | sed -e 's/^dvi//'`
|
|
||||||
result=lib.$ext
|
|
||||||
elif [ x`which dvipdf` != x ] ; then
|
|
||||||
converter=`which dvipdf`
|
|
||||||
ext=.pdf
|
|
||||||
elif [ x`which dvips` != x ] ; then
|
|
||||||
converter=`which dvips`
|
|
||||||
ext=.ps
|
|
||||||
else
|
|
||||||
echo "Can't find a reasonable dvi converter" 1>&2
|
|
||||||
echo "Set DVICVT to refer to one" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# how about a viewer?
|
|
||||||
if [ x$VIEWER != x ] ; then
|
|
||||||
viewer=$VIEWER
|
|
||||||
elif [ $ext = ".ps" -a x`which gv` != x ] ; then
|
|
||||||
viewer=gv
|
|
||||||
elif [ $ext = ".ps" -a x`which gs` != x ] ; then
|
|
||||||
viewer=gs
|
|
||||||
elif [ $ext = ".pdf" -a x`which acroread` != x ] ; then
|
|
||||||
viewer=acroread
|
|
||||||
elif [ $ext = ".pdf" -a "`uname`" = "Darwin" -a x`which open` != x ] ; then
|
|
||||||
viewer=open
|
|
||||||
elif [ $ext = ".pdf" -a x`which acroread` != x ] ; then
|
|
||||||
viewer=acroread
|
|
||||||
else
|
|
||||||
echo "Can't find a reasonable viewer" 1>&2
|
|
||||||
echo "Set VIEWER to refer to one" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# make sure necessary links are in place
|
|
||||||
for f in howto.cls pypaper.sty ; do
|
|
||||||
rm -f $f
|
|
||||||
ln -s $PYSRC/Doc/$f
|
|
||||||
done
|
|
||||||
|
|
||||||
export TEXINPUTS=.:$PYSRC/Doc/texinputs:
|
|
||||||
|
|
||||||
# strip extension in case they gave full filename
|
|
||||||
inp=`basename $1 .tex`
|
|
||||||
|
|
||||||
# create the minimal framework necessary to run section through latex
|
|
||||||
tmpf=lib.tex
|
|
||||||
cat > $tmpf <<EOF
|
|
||||||
\documentclass{manual}
|
|
||||||
|
|
||||||
% NOTE: this file controls which chapters/sections of the library
|
|
||||||
% manual are actually printed. It is easy to customize your manual
|
|
||||||
% by commenting out sections that you are not interested in.
|
|
||||||
|
|
||||||
\title{Python Library Reference}
|
|
||||||
|
|
||||||
\input{boilerplate}
|
|
||||||
|
|
||||||
\makeindex % tell \index to actually write the
|
|
||||||
% .idx file
|
|
||||||
\makemodindex % ... and the module index as well.
|
|
||||||
|
|
||||||
|
|
||||||
\begin{document}
|
|
||||||
|
|
||||||
\maketitle
|
|
||||||
|
|
||||||
\ifhtml
|
|
||||||
\chapter*{Front Matter\label{front}}
|
|
||||||
\fi
|
|
||||||
|
|
||||||
\input{$inp}
|
|
||||||
\end{document}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
latex $tmpf
|
|
||||||
|
|
||||||
$converter lib
|
|
||||||
|
|
||||||
$viewer lib.pdf
|
|
||||||
|
|
||||||
rm -f $tmpf howto.cls pypaper.sty *.idx *.syn
|
|
||||||
rm -f lib.{aux,log}
|
|
@ -1,66 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
|
|
||||||
import string
|
|
||||||
import support
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def collect(fp):
|
|
||||||
names = []
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
line = string.strip(line)
|
|
||||||
if line:
|
|
||||||
names.append(line)
|
|
||||||
else:
|
|
||||||
names = []
|
|
||||||
return names
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
options = support.Options()
|
|
||||||
options.columns = 4
|
|
||||||
options.variables["title"] = "Acknowledgements"
|
|
||||||
options.parse(sys.argv[1:])
|
|
||||||
names = collect(sys.stdin)
|
|
||||||
percol = (len(names) + options.columns - 1) / options.columns
|
|
||||||
colnums = []
|
|
||||||
for i in range(options.columns):
|
|
||||||
colnums.append(percol*i)
|
|
||||||
options.aesop_type = "information"
|
|
||||||
fp = options.get_output_file()
|
|
||||||
fp.write(string.rstrip(options.get_header()) + "\n")
|
|
||||||
fp.write(THANKS + "\n")
|
|
||||||
fp.write('<table width="100%" align="center">\n')
|
|
||||||
for i in range(percol):
|
|
||||||
fp.write(" <tr>\n")
|
|
||||||
for j in colnums:
|
|
||||||
try:
|
|
||||||
fp.write(" <td>%s</td>\n" % names[i + j])
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
fp.write(" </tr>\n")
|
|
||||||
fp.write("</table>\n")
|
|
||||||
fp.write(string.rstrip(options.get_footer()) + "\n")
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
THANKS = '''\
|
|
||||||
|
|
||||||
<p>These people have contributed in some way to the Python
|
|
||||||
documentation. This list is probably not complete -- if you feel that
|
|
||||||
you or anyone else should be on this list, please let us know (send
|
|
||||||
email to <a
|
|
||||||
href="mailto:python-docs@python.org">python-docs@python.org</a>), and
|
|
||||||
we will be glad to correct the problem.</p>
|
|
||||||
|
|
||||||
<p>It is only with the input and contributions of the Python community
|
|
||||||
that Python has such wonderful documentation -- <b>Thank You!</b></p>
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,665 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
"""usage: %(program)s [options...] file ...
|
|
||||||
|
|
||||||
Options specifying formats to build:
|
|
||||||
--html HyperText Markup Language (default)
|
|
||||||
--pdf Portable Document Format
|
|
||||||
--ps PostScript
|
|
||||||
--dvi 'DeVice Indepentent' format from TeX
|
|
||||||
--text ASCII text (requires lynx)
|
|
||||||
|
|
||||||
More than one output format may be specified, or --all.
|
|
||||||
|
|
||||||
HTML options:
|
|
||||||
--address, -a Specify an address for page footers.
|
|
||||||
--dir Specify the directory for HTML output.
|
|
||||||
--link Specify the number of levels to include on each page.
|
|
||||||
--split, -s Specify a section level for page splitting, default: %(max_split_depth)s.
|
|
||||||
--iconserver, -i Specify location of icons (default: ./).
|
|
||||||
--image-type Specify the image type to use in HTML output;
|
|
||||||
values: gif (default), png.
|
|
||||||
--numeric Don't rename the HTML files; just keep node#.html for
|
|
||||||
the filenames.
|
|
||||||
--style Specify the CSS file to use for the output (filename,
|
|
||||||
not a URL).
|
|
||||||
--up-link URL to a parent document.
|
|
||||||
--up-title Title of a parent document.
|
|
||||||
--favicon Icon to display in the browsers location bar.
|
|
||||||
|
|
||||||
Other options:
|
|
||||||
--a4 Format for A4 paper.
|
|
||||||
--letter Format for US letter paper (the default).
|
|
||||||
--help, -H Show this text.
|
|
||||||
--logging, -l Log stdout and stderr to a file (*.how).
|
|
||||||
--debugging, -D Echo commands as they are executed.
|
|
||||||
--keep, -k Keep temporary files around.
|
|
||||||
--quiet, -q Do not print command output to stdout.
|
|
||||||
(stderr is also lost, sorry; see *.how for errors)
|
|
||||||
"""
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import string
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
if not hasattr(os.path, "abspath"):
|
|
||||||
# Python 1.5.1 or earlier
|
|
||||||
def abspath(path):
|
|
||||||
"""Return an absolute path."""
|
|
||||||
if not os.path.isabs(path):
|
|
||||||
path = os.path.join(os.getcwd(), path)
|
|
||||||
return os.path.normpath(path)
|
|
||||||
|
|
||||||
os.path.abspath = abspath
|
|
||||||
|
|
||||||
|
|
||||||
MYDIR = os.path.abspath(sys.path[0])
|
|
||||||
TOPDIR = os.path.dirname(MYDIR)
|
|
||||||
|
|
||||||
ISTFILE = os.path.join(TOPDIR, "texinputs", "python.ist")
|
|
||||||
NODE2LABEL_SCRIPT = os.path.join(MYDIR, "node2label.pl")
|
|
||||||
L2H_INIT_FILE = os.path.join(TOPDIR, "perl", "l2hinit.perl")
|
|
||||||
|
|
||||||
BIBTEX_BINARY = "bibtex"
|
|
||||||
DVIPS_BINARY = "dvips"
|
|
||||||
LATEX_BINARY = "latex"
|
|
||||||
LATEX2HTML_BINARY = "latex2html"
|
|
||||||
LYNX_BINARY = "lynx"
|
|
||||||
MAKEINDEX_BINARY = "makeindex"
|
|
||||||
PDFLATEX_BINARY = "pdflatex"
|
|
||||||
PERL_BINARY = "perl"
|
|
||||||
PYTHON_BINARY = "python"
|
|
||||||
|
|
||||||
|
|
||||||
def usage(options):
|
|
||||||
print __doc__ % options
|
|
||||||
|
|
||||||
def error(options, message, err=2):
|
|
||||||
sys.stdout = sys.stderr
|
|
||||||
print message
|
|
||||||
print
|
|
||||||
usage(options)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
|
|
||||||
class Options:
|
|
||||||
program = os.path.basename(sys.argv[0])
|
|
||||||
#
|
|
||||||
address = ''
|
|
||||||
builddir = None
|
|
||||||
debugging = 0
|
|
||||||
discard_temps = 1
|
|
||||||
have_temps = 0
|
|
||||||
icon_server = "."
|
|
||||||
image_type = "gif"
|
|
||||||
logging = 0
|
|
||||||
max_link_depth = 3
|
|
||||||
max_split_depth = 6
|
|
||||||
paper = "letter"
|
|
||||||
quiet = 0
|
|
||||||
runs = 0
|
|
||||||
numeric = 0
|
|
||||||
global_module_index = None
|
|
||||||
style_file = os.path.join(TOPDIR, "html", "style.css")
|
|
||||||
about_file = os.path.join(TOPDIR, "html", "about.dat")
|
|
||||||
up_link = None
|
|
||||||
up_title = None
|
|
||||||
favicon = None
|
|
||||||
#
|
|
||||||
# 'dvips_safe' is a weird option. It is used mostly to make
|
|
||||||
# LaTeX2HTML not try to be too smart about protecting the user
|
|
||||||
# from a bad version of dvips -- some versions would core dump if
|
|
||||||
# the path to the source DVI contained a dot, and it's appearantly
|
|
||||||
# difficult to determine if the version available has that bug.
|
|
||||||
# This option gets set when PostScript output is requested
|
|
||||||
# (because we're going to run dvips regardless, and we'll either
|
|
||||||
# know it succeeds before LaTeX2HTML is run, or we'll have
|
|
||||||
# detected the failure and bailed), or the user asserts that it's
|
|
||||||
# safe from the command line.
|
|
||||||
#
|
|
||||||
# So, why does LaTeX2HTML think it appropriate to protect the user
|
|
||||||
# from a dvips that's only potentially going to core dump? Only
|
|
||||||
# because they want to avoid doing a lot of work just to have to
|
|
||||||
# bail later with no useful intermediates. Unfortunately, they
|
|
||||||
# bail *before* they know whether dvips will be needed at all.
|
|
||||||
# I've gone around the bush a few times with the LaTeX2HTML
|
|
||||||
# developers over whether this is appropriate behavior, and they
|
|
||||||
# don't seem interested in changing their position.
|
|
||||||
#
|
|
||||||
dvips_safe = 0
|
|
||||||
#
|
|
||||||
DEFAULT_FORMATS = ("html",)
|
|
||||||
ALL_FORMATS = ("dvi", "html", "pdf", "ps", "text")
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.formats = []
|
|
||||||
self.l2h_init_files = []
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
# This is used when formatting the usage message.
|
|
||||||
try:
|
|
||||||
return getattr(self, key)
|
|
||||||
except AttributeError:
|
|
||||||
raise KeyError, key
|
|
||||||
|
|
||||||
def parse(self, args):
|
|
||||||
opts, args = getopt.getopt(args, "Hi:a:s:lDkqr:",
|
|
||||||
["all", "postscript", "help", "iconserver=",
|
|
||||||
"address=", "a4", "letter", "l2h-init=",
|
|
||||||
"link=", "split=", "logging", "debugging",
|
|
||||||
"keep", "quiet", "runs=", "image-type=",
|
|
||||||
"about=", "numeric", "style=", "paper=",
|
|
||||||
"up-link=", "up-title=", "dir=",
|
|
||||||
"global-module-index=", "dvips-safe",
|
|
||||||
"favicon="]
|
|
||||||
+ list(self.ALL_FORMATS))
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt == "--all":
|
|
||||||
self.formats = list(self.ALL_FORMATS)
|
|
||||||
self.dvips_safe = "ps" in self.formats
|
|
||||||
elif opt in ("-H", "--help"):
|
|
||||||
usage(self)
|
|
||||||
sys.exit()
|
|
||||||
elif opt == "--iconserver":
|
|
||||||
self.icon_server = arg
|
|
||||||
elif opt in ("-a", "--address"):
|
|
||||||
self.address = arg
|
|
||||||
elif opt == "--a4":
|
|
||||||
self.paper = "a4"
|
|
||||||
elif opt == "--letter":
|
|
||||||
self.paper = "letter"
|
|
||||||
elif opt == "--link":
|
|
||||||
self.max_link_depth = int(arg)
|
|
||||||
elif opt in ("-s", "--split"):
|
|
||||||
self.max_split_depth = int(arg)
|
|
||||||
elif opt in ("-l", "--logging"):
|
|
||||||
self.logging = self.logging + 1
|
|
||||||
elif opt in ("-D", "--debugging"):
|
|
||||||
self.debugging = self.debugging + 1
|
|
||||||
elif opt in ("-k", "--keep"):
|
|
||||||
self.discard_temps = 0
|
|
||||||
elif opt in ("-q", "--quiet"):
|
|
||||||
self.quiet = 1
|
|
||||||
elif opt in ("-r", "--runs"):
|
|
||||||
self.runs = int(arg)
|
|
||||||
elif opt == "--image-type":
|
|
||||||
self.image_type = arg
|
|
||||||
elif opt == "--about":
|
|
||||||
# always make this absolute:
|
|
||||||
self.about_file = os.path.normpath(
|
|
||||||
os.path.abspath(arg))
|
|
||||||
elif opt == "--numeric":
|
|
||||||
self.numeric = 1
|
|
||||||
elif opt == "--style":
|
|
||||||
self.style_file = os.path.abspath(arg)
|
|
||||||
elif opt == "--l2h-init":
|
|
||||||
self.l2h_init_files.append(os.path.abspath(arg))
|
|
||||||
elif opt == "--favicon":
|
|
||||||
self.favicon = arg
|
|
||||||
elif opt == "--up-link":
|
|
||||||
self.up_link = arg
|
|
||||||
elif opt == "--up-title":
|
|
||||||
self.up_title = arg
|
|
||||||
elif opt == "--global-module-index":
|
|
||||||
self.global_module_index = arg
|
|
||||||
elif opt == "--dir":
|
|
||||||
if os.sep == "\\":
|
|
||||||
arg = re.sub("/", "\\", arg)
|
|
||||||
self.builddir = os.path.expanduser(arg)
|
|
||||||
elif opt == "--paper":
|
|
||||||
self.paper = arg
|
|
||||||
elif opt == "--dvips-safe":
|
|
||||||
self.dvips_safe = 1
|
|
||||||
#
|
|
||||||
# Format specifiers:
|
|
||||||
#
|
|
||||||
elif opt[2:] in self.ALL_FORMATS:
|
|
||||||
self.add_format(opt[2:])
|
|
||||||
elif opt == "--postscript":
|
|
||||||
# synonym for --ps
|
|
||||||
self.add_format("ps")
|
|
||||||
self.initialize()
|
|
||||||
#
|
|
||||||
# return the args to allow the caller access:
|
|
||||||
#
|
|
||||||
return args
|
|
||||||
|
|
||||||
def add_format(self, format):
|
|
||||||
"""Add a format to the formats list if not present."""
|
|
||||||
if not format in self.formats:
|
|
||||||
if format == "ps":
|
|
||||||
# assume this is safe since we're going to run it anyway
|
|
||||||
self.dvips_safe = 1
|
|
||||||
self.formats.append(format)
|
|
||||||
|
|
||||||
def initialize(self):
|
|
||||||
"""Complete initialization. This is needed if parse() isn't used."""
|
|
||||||
# add the default format if no formats were specified:
|
|
||||||
if not self.formats:
|
|
||||||
self.formats = self.DEFAULT_FORMATS
|
|
||||||
# determine the base set of texinputs directories:
|
|
||||||
texinputs = string.split(os.environ.get("TEXINPUTS", ""), os.pathsep)
|
|
||||||
if not texinputs:
|
|
||||||
texinputs = ['']
|
|
||||||
self.base_texinputs = [
|
|
||||||
os.path.join(TOPDIR, "paper-" + self.paper),
|
|
||||||
os.path.join(TOPDIR, "texinputs"),
|
|
||||||
] + texinputs
|
|
||||||
if self.builddir:
|
|
||||||
self.builddir = os.path.abspath(self.builddir)
|
|
||||||
|
|
||||||
|
|
||||||
class Job:
|
|
||||||
latex_runs = 0
|
|
||||||
|
|
||||||
def __init__(self, options, path):
|
|
||||||
self.options = options
|
|
||||||
self.doctype = get_doctype(path)
|
|
||||||
self.filedir, self.doc = split_pathname(path)
|
|
||||||
self.builddir = os.path.abspath(options.builddir or self.doc)
|
|
||||||
if ("html" in options.formats or "text" in options.formats):
|
|
||||||
if not os.path.exists(self.builddir):
|
|
||||||
os.mkdir(self.builddir)
|
|
||||||
self.log_filename = os.path.join(self.builddir, self.doc + ".how")
|
|
||||||
else:
|
|
||||||
self.log_filename = os.path.abspath(self.doc + ".how")
|
|
||||||
if os.path.exists(self.log_filename):
|
|
||||||
os.unlink(self.log_filename)
|
|
||||||
l2hconf = self.doc + ".l2h"
|
|
||||||
if os.path.exists(l2hconf):
|
|
||||||
if os.path.exists(l2hconf + "~"):
|
|
||||||
os.unlink(l2hconf + "~")
|
|
||||||
os.rename(l2hconf, l2hconf + "~")
|
|
||||||
self.l2h_aux_init_file = self.doc + ".l2h"
|
|
||||||
self.write_l2h_aux_init_file()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self.setup_texinputs()
|
|
||||||
formats = self.options.formats
|
|
||||||
if "dvi" in formats or "ps" in formats:
|
|
||||||
self.build_dvi()
|
|
||||||
if "pdf" in formats:
|
|
||||||
self.build_pdf()
|
|
||||||
if "ps" in formats:
|
|
||||||
self.build_ps()
|
|
||||||
if "html" in formats:
|
|
||||||
self.require_temps()
|
|
||||||
self.build_html(self.builddir)
|
|
||||||
if self.options.icon_server == ".":
|
|
||||||
pattern = os.path.join(TOPDIR, "html", "icons",
|
|
||||||
"*." + self.options.image_type)
|
|
||||||
imgs = glob.glob(pattern)
|
|
||||||
if not imgs:
|
|
||||||
self.warning(
|
|
||||||
"Could not locate support images of type %s."
|
|
||||||
% `self.options.image_type`)
|
|
||||||
for fn in imgs:
|
|
||||||
new_fn = os.path.join(self.builddir, os.path.basename(fn))
|
|
||||||
shutil.copyfile(fn, new_fn)
|
|
||||||
if "text" in formats:
|
|
||||||
self.require_temps()
|
|
||||||
tempdir = self.doc
|
|
||||||
need_html = "html" not in formats
|
|
||||||
if self.options.max_split_depth != 1:
|
|
||||||
fp = open(self.l2h_aux_init_file, "a")
|
|
||||||
fp.write("# re-hack this file for --text:\n")
|
|
||||||
l2hoption(fp, "MAX_SPLIT_DEPTH", "1")
|
|
||||||
fp.write("1;\n")
|
|
||||||
fp.close()
|
|
||||||
tempdir = self.doc + "-temp-html"
|
|
||||||
need_html = 1
|
|
||||||
if need_html:
|
|
||||||
self.build_html(tempdir, max_split_depth=1)
|
|
||||||
self.build_text(tempdir)
|
|
||||||
if self.options.discard_temps:
|
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
def setup_texinputs(self):
|
|
||||||
texinputs = [self.filedir] + list(self.options.base_texinputs)
|
|
||||||
os.environ["TEXINPUTS"] = string.join(texinputs, os.pathsep)
|
|
||||||
self.message("TEXINPUTS=" + os.environ["TEXINPUTS"])
|
|
||||||
|
|
||||||
def build_aux(self, binary=None):
|
|
||||||
if binary is None:
|
|
||||||
binary = LATEX_BINARY
|
|
||||||
new_index( "%s.ind" % self.doc, "genindex")
|
|
||||||
new_index("mod%s.ind" % self.doc, "modindex")
|
|
||||||
self.run("%s %s" % (binary, self.doc))
|
|
||||||
self.use_bibtex = check_for_bibtex(self.doc + ".aux")
|
|
||||||
self.latex_runs = 1
|
|
||||||
|
|
||||||
def build_dvi(self):
|
|
||||||
self.use_latex(LATEX_BINARY)
|
|
||||||
|
|
||||||
def build_pdf(self):
|
|
||||||
self.use_latex(PDFLATEX_BINARY)
|
|
||||||
|
|
||||||
def use_latex(self, binary):
|
|
||||||
self.require_temps(binary=binary)
|
|
||||||
if self.latex_runs < 2:
|
|
||||||
if os.path.isfile("mod%s.idx" % self.doc):
|
|
||||||
self.run("%s mod%s.idx" % (MAKEINDEX_BINARY, self.doc))
|
|
||||||
use_indfix = 0
|
|
||||||
if os.path.isfile(self.doc + ".idx"):
|
|
||||||
use_indfix = 1
|
|
||||||
# call to Doc/tools/fix_hack omitted; doesn't appear necessary
|
|
||||||
self.run("%s %s.idx" % (MAKEINDEX_BINARY, self.doc))
|
|
||||||
import indfix
|
|
||||||
indfix.process(self.doc + ".ind")
|
|
||||||
if self.use_bibtex:
|
|
||||||
self.run("%s %s" % (BIBTEX_BINARY, self.doc))
|
|
||||||
self.process_synopsis_files()
|
|
||||||
self.run("%s %s" % (binary, self.doc))
|
|
||||||
self.latex_runs = self.latex_runs + 1
|
|
||||||
if os.path.isfile("mod%s.idx" % self.doc):
|
|
||||||
self.run("%s -s %s mod%s.idx"
|
|
||||||
% (MAKEINDEX_BINARY, ISTFILE, self.doc))
|
|
||||||
if use_indfix:
|
|
||||||
self.run("%s -s %s %s.idx"
|
|
||||||
% (MAKEINDEX_BINARY, ISTFILE, self.doc))
|
|
||||||
indfix.process(self.doc + ".ind")
|
|
||||||
self.process_synopsis_files()
|
|
||||||
#
|
|
||||||
# and now finish it off:
|
|
||||||
#
|
|
||||||
if os.path.isfile(self.doc + ".toc") and binary == PDFLATEX_BINARY:
|
|
||||||
import toc2bkm
|
|
||||||
if self.doctype == "manual":
|
|
||||||
bigpart = "chapter"
|
|
||||||
else:
|
|
||||||
bigpart = "section"
|
|
||||||
toc2bkm.process(self.doc + ".toc", self.doc + ".bkm", bigpart)
|
|
||||||
if self.use_bibtex:
|
|
||||||
self.run("%s %s" % (BIBTEX_BINARY, self.doc))
|
|
||||||
self.run("%s %s" % (binary, self.doc))
|
|
||||||
self.latex_runs = self.latex_runs + 1
|
|
||||||
|
|
||||||
def process_synopsis_files(self):
|
|
||||||
synopsis_files = glob.glob(self.doc + "*.syn")
|
|
||||||
for path in synopsis_files:
|
|
||||||
uniqify_module_table(path)
|
|
||||||
|
|
||||||
def build_ps(self):
|
|
||||||
self.run("%s -N0 -o %s.ps %s" % (DVIPS_BINARY, self.doc, self.doc))
|
|
||||||
|
|
||||||
def build_html(self, builddir, max_split_depth=None):
|
|
||||||
if max_split_depth is None:
|
|
||||||
max_split_depth = self.options.max_split_depth
|
|
||||||
texfile = None
|
|
||||||
for p in string.split(os.environ["TEXINPUTS"], os.pathsep):
|
|
||||||
fn = os.path.join(p, self.doc + ".tex")
|
|
||||||
if os.path.isfile(fn):
|
|
||||||
texfile = fn
|
|
||||||
break
|
|
||||||
if not texfile:
|
|
||||||
self.warning("Could not locate %s.tex; aborting." % self.doc)
|
|
||||||
sys.exit(1)
|
|
||||||
# remove leading ./ (or equiv.); might avoid problems w/ dvips
|
|
||||||
if texfile[:2] == os.curdir + os.sep:
|
|
||||||
texfile = texfile[2:]
|
|
||||||
# build the command line and run LaTeX2HTML:
|
|
||||||
if not os.path.isdir(builddir):
|
|
||||||
os.mkdir(builddir)
|
|
||||||
else:
|
|
||||||
for fname in glob.glob(os.path.join(builddir, "*.html")):
|
|
||||||
os.unlink(fname)
|
|
||||||
args = [LATEX2HTML_BINARY,
|
|
||||||
"-init_file", self.l2h_aux_init_file,
|
|
||||||
"-dir", builddir,
|
|
||||||
texfile
|
|
||||||
]
|
|
||||||
self.run(string.join(args)) # XXX need quoting!
|
|
||||||
# ... postprocess
|
|
||||||
shutil.copyfile(self.options.style_file,
|
|
||||||
os.path.join(builddir, self.doc + ".css"))
|
|
||||||
shutil.copyfile(os.path.join(builddir, self.doc + ".html"),
|
|
||||||
os.path.join(builddir, "index.html"))
|
|
||||||
if max_split_depth != 1:
|
|
||||||
label_file = os.path.join(builddir, "labels.pl")
|
|
||||||
fp = open(label_file)
|
|
||||||
about_node = None
|
|
||||||
target = " = q/about/;\n"
|
|
||||||
x = len(target)
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
if line[-x:] == target:
|
|
||||||
line = fp.readline()
|
|
||||||
m = re.search(r"\|(node\d+\.[a-z]+)\|", line)
|
|
||||||
about_node = m.group(1)
|
|
||||||
shutil.copyfile(os.path.join(builddir, about_node),
|
|
||||||
os.path.join(builddir, "about.html"))
|
|
||||||
break
|
|
||||||
if not self.options.numeric:
|
|
||||||
pwd = os.getcwd()
|
|
||||||
try:
|
|
||||||
os.chdir(builddir)
|
|
||||||
self.run("%s %s *.html" % (PERL_BINARY, NODE2LABEL_SCRIPT))
|
|
||||||
finally:
|
|
||||||
os.chdir(pwd)
|
|
||||||
# These files need to be cleaned up here since builddir there
|
|
||||||
# can be more than one, so we clean each of them.
|
|
||||||
if self.options.discard_temps:
|
|
||||||
for fn in ("images.tex", "images.log", "images.aux"):
|
|
||||||
safe_unlink(os.path.join(builddir, fn))
|
|
||||||
|
|
||||||
def build_text(self, tempdir=None):
|
|
||||||
if tempdir is None:
|
|
||||||
tempdir = self.doc
|
|
||||||
indexfile = os.path.join(tempdir, "index.html")
|
|
||||||
self.run("%s -nolist -dump %s >%s.txt"
|
|
||||||
% (LYNX_BINARY, indexfile, self.doc))
|
|
||||||
|
|
||||||
def require_temps(self, binary=None):
|
|
||||||
if not self.latex_runs:
|
|
||||||
self.build_aux(binary=binary)
|
|
||||||
|
|
||||||
def write_l2h_aux_init_file(self):
|
|
||||||
options = self.options
|
|
||||||
fp = open(self.l2h_aux_init_file, "w")
|
|
||||||
d = string_to_perl(os.path.dirname(L2H_INIT_FILE))
|
|
||||||
fp.write("package main;\n"
|
|
||||||
"push (@INC, '%s');\n"
|
|
||||||
"$mydir = '%s';\n"
|
|
||||||
% (d, d))
|
|
||||||
fp.write(open(L2H_INIT_FILE).read())
|
|
||||||
for filename in options.l2h_init_files:
|
|
||||||
fp.write("\n# initialization code incorporated from:\n# ")
|
|
||||||
fp.write(filename)
|
|
||||||
fp.write("\n")
|
|
||||||
fp.write(open(filename).read())
|
|
||||||
fp.write("\n"
|
|
||||||
"# auxillary init file for latex2html\n"
|
|
||||||
"# generated by mkhowto\n"
|
|
||||||
"$NO_AUTO_LINK = 1;\n"
|
|
||||||
)
|
|
||||||
l2hoption(fp, "ABOUT_FILE", options.about_file)
|
|
||||||
l2hoption(fp, "ICONSERVER", options.icon_server)
|
|
||||||
l2hoption(fp, "IMAGE_TYPE", options.image_type)
|
|
||||||
l2hoption(fp, "ADDRESS", options.address)
|
|
||||||
l2hoption(fp, "MAX_LINK_DEPTH", options.max_link_depth)
|
|
||||||
l2hoption(fp, "MAX_SPLIT_DEPTH", options.max_split_depth)
|
|
||||||
l2hoption(fp, "EXTERNAL_UP_LINK", options.up_link)
|
|
||||||
l2hoption(fp, "EXTERNAL_UP_TITLE", options.up_title)
|
|
||||||
l2hoption(fp, "FAVORITES_ICON", options.favicon)
|
|
||||||
l2hoption(fp, "GLOBAL_MODULE_INDEX", options.global_module_index)
|
|
||||||
l2hoption(fp, "DVIPS_SAFE", options.dvips_safe)
|
|
||||||
fp.write("1;\n")
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
self.__have_temps = 0
|
|
||||||
for pattern in ("%s.aux", "%s.log", "%s.out", "%s.toc", "%s.bkm",
|
|
||||||
"%s.idx", "%s.ilg", "%s.ind", "%s.pla",
|
|
||||||
"%s.bbl", "%s.blg",
|
|
||||||
"mod%s.idx", "mod%s.ind", "mod%s.ilg",
|
|
||||||
):
|
|
||||||
safe_unlink(pattern % self.doc)
|
|
||||||
map(safe_unlink, glob.glob(self.doc + "*.syn"))
|
|
||||||
for spec in ("IMG*", "*.pl", "WARNINGS", "index.dat", "modindex.dat"):
|
|
||||||
pattern = os.path.join(self.doc, spec)
|
|
||||||
map(safe_unlink, glob.glob(pattern))
|
|
||||||
if "dvi" not in self.options.formats:
|
|
||||||
safe_unlink(self.doc + ".dvi")
|
|
||||||
if os.path.isdir(self.doc + "-temp-html"):
|
|
||||||
shutil.rmtree(self.doc + "-temp-html", ignore_errors=1)
|
|
||||||
if not self.options.logging:
|
|
||||||
os.unlink(self.log_filename)
|
|
||||||
if not self.options.debugging:
|
|
||||||
os.unlink(self.l2h_aux_init_file)
|
|
||||||
|
|
||||||
def run(self, command):
|
|
||||||
self.message(command)
|
|
||||||
if sys.platform.startswith("win"):
|
|
||||||
rc = os.system(command)
|
|
||||||
else:
|
|
||||||
rc = os.system("(%s) </dev/null >>%s 2>&1"
|
|
||||||
% (command, self.log_filename))
|
|
||||||
if rc:
|
|
||||||
self.warning(
|
|
||||||
"Session transcript and error messages are in %s."
|
|
||||||
% self.log_filename)
|
|
||||||
if hasattr(os, "WIFEXITED"):
|
|
||||||
if os.WIFEXITED(rc):
|
|
||||||
self.warning("Exited with status %s." % os.WEXITSTATUS(rc))
|
|
||||||
else:
|
|
||||||
self.warning("Killed by signal %s." % os.WSTOPSIG(rc))
|
|
||||||
else:
|
|
||||||
self.warning("Return code: %s" % rc)
|
|
||||||
sys.stderr.write("The relevant lines from the transcript are:\n")
|
|
||||||
sys.stderr.write("-" * 72 + "\n")
|
|
||||||
sys.stderr.writelines(get_run_transcript(self.log_filename))
|
|
||||||
sys.exit(rc)
|
|
||||||
|
|
||||||
def message(self, msg):
|
|
||||||
msg = "+++ " + msg
|
|
||||||
if not self.options.quiet:
|
|
||||||
print msg
|
|
||||||
self.log(msg + "\n")
|
|
||||||
|
|
||||||
def warning(self, msg):
|
|
||||||
msg = "*** %s\n" % msg
|
|
||||||
sys.stderr.write(msg)
|
|
||||||
self.log(msg)
|
|
||||||
|
|
||||||
def log(self, msg):
|
|
||||||
fp = open(self.log_filename, "a")
|
|
||||||
fp.write(msg)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
def get_run_transcript(filename):
|
|
||||||
"""Return lines from the transcript file for the most recent run() call."""
|
|
||||||
fp = open(filename)
|
|
||||||
lines = fp.readlines()
|
|
||||||
fp.close()
|
|
||||||
lines.reverse()
|
|
||||||
L = []
|
|
||||||
for line in lines:
|
|
||||||
L.append(line)
|
|
||||||
if line[:4] == "+++ ":
|
|
||||||
break
|
|
||||||
L.reverse()
|
|
||||||
return L
|
|
||||||
|
|
||||||
|
|
||||||
def safe_unlink(path):
|
|
||||||
"""Unlink a file without raising an error if it doesn't exist."""
|
|
||||||
try:
|
|
||||||
os.unlink(path)
|
|
||||||
except os.error:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def split_pathname(path):
|
|
||||||
path = os.path.abspath(path)
|
|
||||||
dirname, basename = os.path.split(path)
|
|
||||||
if basename[-4:] == ".tex":
|
|
||||||
basename = basename[:-4]
|
|
||||||
return dirname, basename
|
|
||||||
|
|
||||||
|
|
||||||
_doctype_rx = re.compile(r"\\documentclass(?:\[[^]]*\])?{([a-zA-Z]*)}")
|
|
||||||
def get_doctype(path):
|
|
||||||
fp = open(path)
|
|
||||||
doctype = None
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
m = _doctype_rx.match(line)
|
|
||||||
if m:
|
|
||||||
doctype = m.group(1)
|
|
||||||
break
|
|
||||||
fp.close()
|
|
||||||
return doctype
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
options = Options()
|
|
||||||
try:
|
|
||||||
args = options.parse(sys.argv[1:])
|
|
||||||
except getopt.error, msg:
|
|
||||||
error(options, msg)
|
|
||||||
if not args:
|
|
||||||
# attempt to locate single .tex file in current directory:
|
|
||||||
args = glob.glob("*.tex")
|
|
||||||
if not args:
|
|
||||||
error(options, "No file to process.")
|
|
||||||
if len(args) > 1:
|
|
||||||
error(options, "Could not deduce which files should be processed.")
|
|
||||||
#
|
|
||||||
# parameters are processed, let's go!
|
|
||||||
#
|
|
||||||
for path in args:
|
|
||||||
Job(options, path).build()
|
|
||||||
|
|
||||||
|
|
||||||
def l2hoption(fp, option, value):
|
|
||||||
if value:
|
|
||||||
fp.write('$%s = "%s";\n' % (option, string_to_perl(str(value))))
|
|
||||||
|
|
||||||
|
|
||||||
_to_perl = {}
|
|
||||||
for c in map(chr, range(1, 256)):
|
|
||||||
_to_perl[c] = c
|
|
||||||
_to_perl["@"] = "\\@"
|
|
||||||
_to_perl["$"] = "\\$"
|
|
||||||
_to_perl['"'] = '\\"'
|
|
||||||
|
|
||||||
def string_to_perl(s):
|
|
||||||
return string.join(map(_to_perl.get, s), '')
|
|
||||||
|
|
||||||
|
|
||||||
def check_for_bibtex(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
pos = string.find(fp.read(), r"\bibdata{")
|
|
||||||
fp.close()
|
|
||||||
return pos >= 0
|
|
||||||
|
|
||||||
def uniqify_module_table(filename):
|
|
||||||
lines = open(filename).readlines()
|
|
||||||
if len(lines) > 1:
|
|
||||||
if lines[-1] == lines[-2]:
|
|
||||||
del lines[-1]
|
|
||||||
open(filename, "w").writelines(lines)
|
|
||||||
|
|
||||||
|
|
||||||
def new_index(filename, label="genindex"):
|
|
||||||
fp = open(filename, "w")
|
|
||||||
fp.write(r"""\
|
|
||||||
\begin{theindex}
|
|
||||||
\label{%s}
|
|
||||||
\end{theindex}
|
|
||||||
""" % label)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,63 +0,0 @@
|
|||||||
#! /bin/sh
|
|
||||||
# -*- Ksh -*-
|
|
||||||
|
|
||||||
# Script to drive the HTML-info conversion process.
|
|
||||||
# Pass in upto three parameters:
|
|
||||||
# - the name of the main tex file
|
|
||||||
# - the name of the output file in texi format (optional)
|
|
||||||
# - the name of the output file in info format (optional)
|
|
||||||
#
|
|
||||||
# Written by Fred L. Drake, Jr. <fdrake@acm.org>
|
|
||||||
|
|
||||||
EMACS=${EMACS:-emacs}
|
|
||||||
MAKEINFO=${MAKEINFO:-makeinfo}
|
|
||||||
|
|
||||||
|
|
||||||
# Normalize file name since something called by html2texi.pl seems to
|
|
||||||
# screw up with relative path names.
|
|
||||||
FILENAME="$1"
|
|
||||||
DOCDIR=`dirname "$FILENAME"`
|
|
||||||
DOCFILE=`basename "$FILENAME"`
|
|
||||||
DOCNAME=`basename "$FILENAME" .tex`
|
|
||||||
if [ $# -gt 1 ]; then
|
|
||||||
TEXINAME="$2"
|
|
||||||
else
|
|
||||||
TEXINAME="python-$DOCNAME.texi"
|
|
||||||
fi
|
|
||||||
if [ $# -gt 2 ]; then
|
|
||||||
INFONAME="$3"
|
|
||||||
else
|
|
||||||
INFONAME="python-$DOCNAME.info"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Now build the real directory names, and locate our support stuff:
|
|
||||||
WORKDIR=`pwd`
|
|
||||||
cd `dirname $0`
|
|
||||||
TOOLSDIR=`pwd`
|
|
||||||
cd $DOCDIR
|
|
||||||
DOCDIR=`pwd`
|
|
||||||
cd $WORKDIR
|
|
||||||
|
|
||||||
|
|
||||||
run() {
|
|
||||||
# show what we're doing, like make does:
|
|
||||||
echo "$*"
|
|
||||||
"$@" || exit $?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# generate the Texinfo file:
|
|
||||||
|
|
||||||
run $EMACS -batch -q --no-site-file -l $TOOLSDIR/py2texi.el \
|
|
||||||
--eval "(setq py2texi-dirs '(\"./\" \"../texinputs/\" \"$DOCDIR\"))" \
|
|
||||||
--eval "(setq py2texi-texi-file-name \"$TEXINAME\")" \
|
|
||||||
--eval "(setq py2texi-info-file-name \"$INFONAME\")" \
|
|
||||||
--eval "(py2texi \"$DOCDIR/$DOCFILE\")" \
|
|
||||||
-f kill-emacs
|
|
||||||
echo Done
|
|
||||||
|
|
||||||
|
|
||||||
# generate the .info files:
|
|
||||||
|
|
||||||
run $MAKEINFO --footnote-style end --fill-column 72 \
|
|
||||||
--paragraph-indent 0 --output=$INFONAME $TEXINAME
|
|
@ -1,158 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
|
|
||||||
"""usage: %(program)s [options] file...
|
|
||||||
|
|
||||||
Supported options:
|
|
||||||
|
|
||||||
--address addr
|
|
||||||
-a addr Set the address text to include at the end of the generated
|
|
||||||
HTML; this should be used for contact information.
|
|
||||||
--columns cols
|
|
||||||
-c cols Set the number of columns each index section should be
|
|
||||||
displayed in. The default is 1.
|
|
||||||
--help
|
|
||||||
-h Display this help message.
|
|
||||||
--letters
|
|
||||||
-l Split the output into sections by letter.
|
|
||||||
--output file
|
|
||||||
-o file Write output to 'file' instead of standard out.
|
|
||||||
--iconserver is Use 'is' as the directory containing icons for the
|
|
||||||
navigation bar. The default is 'icons'.
|
|
||||||
--title str Set the page title to 'str'. The default is 'Global
|
|
||||||
Module Index'.
|
|
||||||
--uplink url Set the upward link URL. The default is './'.
|
|
||||||
--uptitle str Set the upward link title. The default is 'Python
|
|
||||||
Documentation Index'.
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from xml.sax.saxutils import quoteattr
|
|
||||||
|
|
||||||
import buildindex
|
|
||||||
import support
|
|
||||||
|
|
||||||
|
|
||||||
class IndexOptions(support.Options):
|
|
||||||
aesop_type = "links"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
support.Options.__init__(self)
|
|
||||||
self.add_args("l", ["letters"])
|
|
||||||
self.letters = 0
|
|
||||||
|
|
||||||
def handle_option(self, opt, val):
|
|
||||||
if opt in ("-l", "--letters"):
|
|
||||||
self.letters = 1
|
|
||||||
|
|
||||||
def usage(self):
|
|
||||||
program = os.path.basename(sys.argv[0])
|
|
||||||
print __doc__ % {"program": program}
|
|
||||||
|
|
||||||
links = [
|
|
||||||
('author', 'acks.html', 'Acknowledgements'),
|
|
||||||
('help', 'about.html', 'About the Python Documentation'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_header(self):
|
|
||||||
header = support.Options.get_header(self)
|
|
||||||
s = ''
|
|
||||||
for rel, href, title in self.links:
|
|
||||||
s += '<link rel="%s" href="%s"' % (rel, href)
|
|
||||||
if title:
|
|
||||||
s += ' title=' + quoteattr(title)
|
|
||||||
s += '>\n '
|
|
||||||
return header.replace("<link ", s + "<link ", 1)
|
|
||||||
|
|
||||||
|
|
||||||
class Node(buildindex.Node):
|
|
||||||
def __init__(self, link, str, seqno, platinfo):
|
|
||||||
self.annotation = platinfo or None
|
|
||||||
if str[0][-5:] == "</tt>":
|
|
||||||
str = str[:-5]
|
|
||||||
self.modname = str
|
|
||||||
buildindex.Node.__init__(self, link, self.modname, seqno)
|
|
||||||
if platinfo:
|
|
||||||
s = '<tt class="module">%s</tt> %s' \
|
|
||||||
% (self.modname, self.annotation)
|
|
||||||
else:
|
|
||||||
s = '<tt class="module">%s</tt>' % str
|
|
||||||
self.text = [s]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
if self.annotation:
|
|
||||||
return '<tt class="module">%s</tt> %s' \
|
|
||||||
% (self.modname, self.annotation)
|
|
||||||
else:
|
|
||||||
return '<tt class="module">%s</tt>' % self.modname
|
|
||||||
|
|
||||||
_rx = re.compile(
|
|
||||||
"<dt><a href=['\"](module-.*\.html)(?:#l2h-\d+)?['\"]>"
|
|
||||||
"<tt class=['\"]module['\"]>([a-zA-Z_][a-zA-Z0-9_.]*)</tt>\s*(<em>"
|
|
||||||
"\(<span class=['\"]platform['\"]>.*</span>\)</em>)?</a>")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
options = IndexOptions()
|
|
||||||
options.variables["title"] = "Global Module Index"
|
|
||||||
options.parse(sys.argv[1:])
|
|
||||||
args = options.args
|
|
||||||
if not args:
|
|
||||||
args = ["-"]
|
|
||||||
#
|
|
||||||
# Collect the input data:
|
|
||||||
#
|
|
||||||
nodes = []
|
|
||||||
has_plat_flag = 0
|
|
||||||
for ifn in args:
|
|
||||||
if ifn == "-":
|
|
||||||
ifp = sys.stdin
|
|
||||||
dirname = ''
|
|
||||||
else:
|
|
||||||
ifp = open(ifn)
|
|
||||||
dirname = os.path.dirname(ifn)
|
|
||||||
while 1:
|
|
||||||
line = ifp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
m = _rx.match(line)
|
|
||||||
if m:
|
|
||||||
# This line specifies a module!
|
|
||||||
basename, modname, platinfo = m.group(1, 2, 3)
|
|
||||||
has_plat_flag = has_plat_flag or platinfo
|
|
||||||
linkfile = os.path.join(dirname, basename)
|
|
||||||
nodes.append(Node('<a href="%s">' % linkfile, modname,
|
|
||||||
len(nodes), platinfo))
|
|
||||||
ifp.close()
|
|
||||||
#
|
|
||||||
# Generate all output:
|
|
||||||
#
|
|
||||||
num_nodes = len(nodes)
|
|
||||||
# Here's the HTML generation:
|
|
||||||
parts = [options.get_header(),
|
|
||||||
buildindex.process_nodes(nodes, options.columns, options.letters),
|
|
||||||
options.get_footer(),
|
|
||||||
]
|
|
||||||
if has_plat_flag:
|
|
||||||
parts.insert(1, PLAT_DISCUSS)
|
|
||||||
html = ''.join(parts)
|
|
||||||
program = os.path.basename(sys.argv[0])
|
|
||||||
fp = options.get_output_file()
|
|
||||||
fp.write(html.rstrip() + "\n")
|
|
||||||
if options.outputfile == "-":
|
|
||||||
sys.stderr.write("%s: %d index nodes\n" % (program, num_nodes))
|
|
||||||
else:
|
|
||||||
print
|
|
||||||
print "%s: %d index nodes" % (program, num_nodes)
|
|
||||||
|
|
||||||
|
|
||||||
PLAT_DISCUSS = """
|
|
||||||
<p> Some module names are followed by an annotation indicating what
|
|
||||||
platform they are available on.</p>
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,90 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
#
|
|
||||||
# Simple script to create the table that lists the packages available
|
|
||||||
# for download. This expects the downloadable files and the Makefile
|
|
||||||
# to be in the current directory.
|
|
||||||
#
|
|
||||||
# The output of this script can be pasted directly into the download
|
|
||||||
# page for the documentation.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from os.path import isfile
|
|
||||||
|
|
||||||
|
|
||||||
PKG_TYPES = [
|
|
||||||
# human name, filename prefix
|
|
||||||
("HTML", "html"),
|
|
||||||
("PDF (US-Letter)", "pdf-letter"),
|
|
||||||
("PDF (A4)", "pdf-a4"),
|
|
||||||
("PostScript (US-Letter)", "postscript-letter"),
|
|
||||||
("PostScript (A4)", "postscript-a4"),
|
|
||||||
("GNU info", "info"),
|
|
||||||
("iSilo", "isilo"),
|
|
||||||
("LaTeX", "latex"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
fp = open("Makefile")
|
|
||||||
for line in fp:
|
|
||||||
line = line.replace('=', ' ', 1)
|
|
||||||
parts = line.split()
|
|
||||||
if parts[:1] == ["RELEASE"]:
|
|
||||||
release = parts[1]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print >>sys.stderr, "Could not locate RELEASE in Makefile."
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print '''\
|
|
||||||
<table border="1" cellpadding="3" align="center">
|
|
||||||
<thead>
|
|
||||||
<tr bgcolor="#99ccff"><th rowspan="2">Content</th>
|
|
||||||
<th colspan="3">Format</th>
|
|
||||||
</tr>
|
|
||||||
<tr bgcolor="#99ccff"><th>ZIP</th><th>GZip</th><th>BZip2</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>'''
|
|
||||||
|
|
||||||
# formatted using FILE_TEMPLATE % (release, prefix, release, extension)
|
|
||||||
FILE_TEMPLATE = '''\
|
|
||||||
<td><a href="../../ftp/python/doc/%s/%s-%s%s"
|
|
||||||
>%dK</a></td>'''
|
|
||||||
|
|
||||||
NO_FILE_TEMPLATE = '''\
|
|
||||||
<td> </td>'''
|
|
||||||
|
|
||||||
def get_size(prefix, ext):
|
|
||||||
fn = "%s-%s%s" % (prefix, release, ext)
|
|
||||||
return int(round(os.path.getsize(fn) / 1024.0))
|
|
||||||
|
|
||||||
def get_file_cell(prefix, ext, have):
|
|
||||||
if have:
|
|
||||||
kb = get_size(prefix, ext)
|
|
||||||
return FILE_TEMPLATE % (release, prefix, release, ext, kb)
|
|
||||||
else:
|
|
||||||
return NO_FILE_TEMPLATE
|
|
||||||
|
|
||||||
for name, prefix in PKG_TYPES:
|
|
||||||
zip_fn = "%s-%s.zip" % (prefix, release)
|
|
||||||
tgz_fn = "%s-%s.tgz" % (prefix, release)
|
|
||||||
bz2_fn = "%s-%s.tar.bz2" % (prefix, release)
|
|
||||||
|
|
||||||
have_zip = isfile(zip_fn)
|
|
||||||
have_tgz = isfile(tgz_fn)
|
|
||||||
have_bz2 = isfile(bz2_fn)
|
|
||||||
|
|
||||||
if have_zip or have_tgz or have_bz2:
|
|
||||||
print " <tr><td>%s</td>" % name
|
|
||||||
|
|
||||||
print get_file_cell(prefix, ".zip", have_zip)
|
|
||||||
print get_file_cell(prefix, ".tgz", have_tgz)
|
|
||||||
print get_file_cell(prefix, ".tar.bz2", have_bz2)
|
|
||||||
|
|
||||||
print " </tr>"
|
|
||||||
|
|
||||||
print '''\
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
'''
|
|
@ -1,164 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
# -*- Python -*-
|
|
||||||
|
|
||||||
"""%(program)s - script to create the latex source distribution
|
|
||||||
|
|
||||||
usage:
|
|
||||||
%(program)s [-t|--tools] release [tag]
|
|
||||||
|
|
||||||
with -t|--tools: doesn't include the documents, only the framework
|
|
||||||
|
|
||||||
without [tag]: generate from the current version that's checked in
|
|
||||||
(*NOT* what's in the current directory!)
|
|
||||||
|
|
||||||
with [tag]: generate from the named tag
|
|
||||||
"""
|
|
||||||
#* should be modified to get the Python version number automatically
|
|
||||||
# from the Makefile or someplace.
|
|
||||||
|
|
||||||
import getopt
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
import cvsinfo
|
|
||||||
|
|
||||||
|
|
||||||
quiet = 0
|
|
||||||
rx = re.compile(r":ext:(?:[a-zA-Z0-9]+)@cvs\.([a-zA-Z0-9]+).sourceforge.net:"
|
|
||||||
r"/cvsroot/\1")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
global quiet
|
|
||||||
try:
|
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "abgtzq",
|
|
||||||
["all", "bzip2", "gzip", "tools", "zip",
|
|
||||||
"quiet"])
|
|
||||||
except getopt.error, e:
|
|
||||||
usage(warning=str(e))
|
|
||||||
sys.exit(2)
|
|
||||||
if len(args) not in (1, 2):
|
|
||||||
usage(warning="wrong number of parameters")
|
|
||||||
sys.exit(2)
|
|
||||||
tools = 0
|
|
||||||
formats = {}
|
|
||||||
for opt, arg in opts:
|
|
||||||
if opt in ("-t", "--tools"):
|
|
||||||
tools = 1
|
|
||||||
elif opt in ("-q", "--quiet"):
|
|
||||||
quiet = quiet + 1
|
|
||||||
elif opt in ("-b", "--bzip2"):
|
|
||||||
formats["bzip2"] = 1
|
|
||||||
elif opt in ("-g", "--gzip"):
|
|
||||||
formats["gzip"] = 1
|
|
||||||
elif opt in ("-z", "--zip"):
|
|
||||||
formats["zip"] = 1
|
|
||||||
elif opt in ("-a", "--all"):
|
|
||||||
formats["bzip2"] = 1
|
|
||||||
formats["gzip"] = 1
|
|
||||||
formats["zip"] = 1
|
|
||||||
if formats:
|
|
||||||
# make order human-predictable
|
|
||||||
formats = formats.keys()
|
|
||||||
formats.sort()
|
|
||||||
else:
|
|
||||||
formats = ["gzip"]
|
|
||||||
release = args[0]
|
|
||||||
cvstag = None
|
|
||||||
if len(args) > 1:
|
|
||||||
cvstag = args[1]
|
|
||||||
tempdir = tempfile.mktemp()
|
|
||||||
os.mkdir(tempdir)
|
|
||||||
pkgdir = os.path.join(tempdir, "Python-Docs-" + release)
|
|
||||||
os.mkdir(pkgdir)
|
|
||||||
pwd = os.getcwd()
|
|
||||||
mydir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
|
||||||
info = cvsinfo.RepositoryInfo(mydir)
|
|
||||||
cvsroot = info.get_cvsroot()
|
|
||||||
m = rx.match(cvsroot)
|
|
||||||
if m:
|
|
||||||
# If this is an authenticated SourceForge repository, convert to
|
|
||||||
# anonymous usage for the export/checkout, since that avoids the
|
|
||||||
# SSH overhead.
|
|
||||||
group = m.group(1)
|
|
||||||
cvsroot = ":pserver:anonymous@cvs.%s.sourceforge.net:/cvsroot/%s" \
|
|
||||||
% (group, group)
|
|
||||||
# For some reason, SourceForge/CVS doesn't seem to care that we
|
|
||||||
# might not have done a "cvs login" to the anonymous server.
|
|
||||||
# That avoids a lot of painful gunk here.
|
|
||||||
os.chdir(tempdir)
|
|
||||||
if not quiet:
|
|
||||||
print "--- current directory is:", pkgdir
|
|
||||||
if cvstag:
|
|
||||||
run("cvs -d%s export -r %s -d Python-Docs-%s python/dist/src/Doc"
|
|
||||||
% (cvsroot, cvstag, release))
|
|
||||||
else:
|
|
||||||
run("cvs -Q -d%s checkout -d Python-Docs-%s python/dist/src/Doc"
|
|
||||||
% (cvsroot, release))
|
|
||||||
# remove CVS directories
|
|
||||||
for p in ('*/CVS', '*/*/CVS', '*/*/*/CVS'):
|
|
||||||
map(shutil.rmtree, glob.glob(p))
|
|
||||||
for f in ('.cvsignore', '*/.cvsignore'):
|
|
||||||
map(os.unlink, glob.glob(f))
|
|
||||||
LICENSE = os.path.normpath(
|
|
||||||
os.path.join(mydir, os.pardir, os.pardir, "LICENSE"))
|
|
||||||
shutil.copyfile(LICENSE, "LICENSE")
|
|
||||||
if tools:
|
|
||||||
archive = "doctools-" + release
|
|
||||||
# we don't want the actual documents in this case:
|
|
||||||
for d in ("api", "dist", "doc", "ext", "inst",
|
|
||||||
"lib", "mac", "ref", "tut"):
|
|
||||||
shutil.rmtree(os.path.join(pkgdir, d))
|
|
||||||
else:
|
|
||||||
archive = "latex-" + release
|
|
||||||
|
|
||||||
# XXX should also remove the .cvsignore files at this point
|
|
||||||
|
|
||||||
os.chdir(tempdir)
|
|
||||||
archive = os.path.join(pwd, archive)
|
|
||||||
for format in formats:
|
|
||||||
if format == "bzip2":
|
|
||||||
run("tar cf - Python-Docs-%s | bzip2 -9 >%s.tar.bz2"
|
|
||||||
% (release, archive))
|
|
||||||
elif format == "gzip":
|
|
||||||
run("tar cf - Python-Docs-%s | gzip -9 >%s.tgz"
|
|
||||||
% (release, archive))
|
|
||||||
elif format == "zip":
|
|
||||||
if os.path.exists(archive + ".zip"):
|
|
||||||
os.unlink(archive + ".zip")
|
|
||||||
run("zip -q -r9 %s.zip Python-Docs-%s"
|
|
||||||
% (archive, release))
|
|
||||||
|
|
||||||
# clean up the work area:
|
|
||||||
os.chdir(pwd)
|
|
||||||
shutil.rmtree(tempdir)
|
|
||||||
|
|
||||||
|
|
||||||
def run(cmd):
|
|
||||||
if quiet < 2:
|
|
||||||
print "+++", cmd
|
|
||||||
if quiet:
|
|
||||||
cmd = "%s >/dev/null" % cmd
|
|
||||||
rc = os.system(cmd)
|
|
||||||
if rc:
|
|
||||||
sys.exit(rc)
|
|
||||||
|
|
||||||
|
|
||||||
def usage(warning=None):
|
|
||||||
stdout = sys.stdout
|
|
||||||
sys.stdout = sys.stderr
|
|
||||||
program = os.path.basename(sys.argv[0])
|
|
||||||
try:
|
|
||||||
if warning:
|
|
||||||
print "%s: %s\n" % (program, warning)
|
|
||||||
print __doc__ % {"program": program}
|
|
||||||
finally:
|
|
||||||
sys.stdout = stdout
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,71 +0,0 @@
|
|||||||
#! /usr/bin/env perl
|
|
||||||
|
|
||||||
# On Cygwin, we actually have to generate a temporary file when doing
|
|
||||||
# the inplace edit, or we'll get permission errors. Not sure who's
|
|
||||||
# bug this is, except that it isn't ours. To deal with this, we
|
|
||||||
# generate backups during the edit phase and remove them at the end.
|
|
||||||
#
|
|
||||||
use English;
|
|
||||||
$INPLACE_EDIT = '.bak';
|
|
||||||
|
|
||||||
# read the labels, then reverse the mappings
|
|
||||||
require "labels.pl";
|
|
||||||
|
|
||||||
%nodes = ();
|
|
||||||
my $key;
|
|
||||||
# sort so that we get a consistent assignment for nodes with multiple labels
|
|
||||||
foreach $label (sort keys %external_labels) {
|
|
||||||
#
|
|
||||||
# If the label can't be used as a filename on non-Unix platforms,
|
|
||||||
# skip it. Such labels may be used internally within the documentation,
|
|
||||||
# but will never be used for filename generation.
|
|
||||||
#
|
|
||||||
if ($label =~ /^([-.a-zA-Z0-9]+)$/) {
|
|
||||||
$key = $external_labels{$label};
|
|
||||||
$key =~ s|^/||;
|
|
||||||
$nodes{$key} = $label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# This adds the "internal" labels added for indexing. These labels will not
|
|
||||||
# be used for file names.
|
|
||||||
require "intlabels.pl";
|
|
||||||
foreach $label (keys %internal_labels) {
|
|
||||||
$key = $internal_labels{$label};
|
|
||||||
$key =~ s|^/||;
|
|
||||||
if (defined($nodes{$key})) {
|
|
||||||
$nodes{$label} = $nodes{$key};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# collect labels that have been used
|
|
||||||
%newnames = ();
|
|
||||||
|
|
||||||
while (<>) {
|
|
||||||
# don't want to do one s/// per line per node
|
|
||||||
# so look for lines with hrefs, then do s/// on nodes present
|
|
||||||
if (/(HREF|href)=[\"\']node\d+\.html[\#\"\']/) {
|
|
||||||
@parts = split(/(HREF|href)\=[\"\']/);
|
|
||||||
shift @parts;
|
|
||||||
for $node (@parts) {
|
|
||||||
$node =~ s/[\#\"\'].*$//g;
|
|
||||||
chomp($node);
|
|
||||||
if (defined($nodes{$node})) {
|
|
||||||
$label = $nodes{$node};
|
|
||||||
if (s/(HREF|href)=([\"\'])$node([\#\"\'])/href=$2$label.html$3/g) {
|
|
||||||
s/(HREF|href)=([\"\'])$label.html/href=$2$label.html/g;
|
|
||||||
$newnames{$node} = "$label.html";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach $oldname (keys %newnames) {
|
|
||||||
rename($oldname, $newnames{$oldname});
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach $filename (glob('*.bak')) {
|
|
||||||
unlink($filename);
|
|
||||||
}
|
|
@ -1,471 +0,0 @@
|
|||||||
"""
|
|
||||||
Makes the necesary files to convert from plain html of
|
|
||||||
Python 1.5 and 1.5.x Documentation to
|
|
||||||
Microsoft HTML Help format version 1.1
|
|
||||||
Doesn't change the html's docs.
|
|
||||||
|
|
||||||
by hernan.foffani@iname.com
|
|
||||||
no copyright and no responsabilities.
|
|
||||||
|
|
||||||
modified by Dale Nagata for Python 1.5.2
|
|
||||||
|
|
||||||
Renamed from make_chm.py to prechm.py, and checked into the Python
|
|
||||||
project, 19-Apr-2002 by Tim Peters. Assorted modifications by Tim
|
|
||||||
and Fred Drake. Obtained from Robin Dunn's .chm packaging of the
|
|
||||||
Python 2.2 docs, at <http://alldunn.com/python/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
from formatter import NullWriter, AbstractFormatter
|
|
||||||
from htmllib import HTMLParser
|
|
||||||
import getopt
|
|
||||||
import cgi
|
|
||||||
|
|
||||||
usage_mode = '''
|
|
||||||
Usage: make_chm.py [-c] [-k] [-p] [-v 1.5[.x]] filename
|
|
||||||
-c: does not build filename.hhc (Table of Contents)
|
|
||||||
-k: does not build filename.hhk (Index)
|
|
||||||
-p: does not build filename.hhp (Project File)
|
|
||||||
-v 1.5[.x]: makes help for the python 1.5[.x] docs
|
|
||||||
(default is python 1.5.2 docs)
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Project file (*.hhp) template. 'arch' is the file basename (like
|
|
||||||
# the pythlp in pythlp.hhp); 'version' is the doc version number (like
|
|
||||||
# the 2.2 in Python 2.2).
|
|
||||||
# The magical numbers in the long line under [WINDOWS] set most of the
|
|
||||||
# user-visible features (visible buttons, tabs, etc).
|
|
||||||
# About 0x10384e: This defines the buttons in the help viewer. The
|
|
||||||
# following defns are taken from htmlhelp.h. Not all possibilities
|
|
||||||
# actually work, and not all those that work are available from the Help
|
|
||||||
# Workshop GUI. In particular, the Zoom/Font button works and is not
|
|
||||||
# available from the GUI. The ones we're using are marked with 'x':
|
|
||||||
#
|
|
||||||
# 0x000002 Hide/Show x
|
|
||||||
# 0x000004 Back x
|
|
||||||
# 0x000008 Forward x
|
|
||||||
# 0x000010 Stop
|
|
||||||
# 0x000020 Refresh
|
|
||||||
# 0x000040 Home x
|
|
||||||
# 0x000080 Forward
|
|
||||||
# 0x000100 Back
|
|
||||||
# 0x000200 Notes
|
|
||||||
# 0x000400 Contents
|
|
||||||
# 0x000800 Locate x
|
|
||||||
# 0x001000 Options x
|
|
||||||
# 0x002000 Print x
|
|
||||||
# 0x004000 Index
|
|
||||||
# 0x008000 Search
|
|
||||||
# 0x010000 History
|
|
||||||
# 0x020000 Favorites
|
|
||||||
# 0x040000 Jump 1
|
|
||||||
# 0x080000 Jump 2
|
|
||||||
# 0x100000 Zoom/Font x
|
|
||||||
# 0x200000 TOC Next
|
|
||||||
# 0x400000 TOC Prev
|
|
||||||
|
|
||||||
project_template = '''
|
|
||||||
[OPTIONS]
|
|
||||||
Compiled file=%(arch)s.chm
|
|
||||||
Contents file=%(arch)s.hhc
|
|
||||||
Default Window=%(arch)s
|
|
||||||
Default topic=index.html
|
|
||||||
Display compile progress=No
|
|
||||||
Full text search stop list file=%(arch)s.stp
|
|
||||||
Full-text search=Yes
|
|
||||||
Index file=%(arch)s.hhk
|
|
||||||
Language=0x409
|
|
||||||
Title=Python %(version)s Documentation
|
|
||||||
|
|
||||||
[WINDOWS]
|
|
||||||
%(arch)s="Python %(version)s Documentation","%(arch)s.hhc","%(arch)s.hhk",\
|
|
||||||
"index.html","index.html",,,,,0x63520,220,0x10384e,[271,372,740,718],,,,,,,0
|
|
||||||
|
|
||||||
[FILES]
|
|
||||||
'''
|
|
||||||
|
|
||||||
contents_header = '''\
|
|
||||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
|
||||||
<HTML>
|
|
||||||
<HEAD>
|
|
||||||
<meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">
|
|
||||||
<!-- Sitemap 1.0 -->
|
|
||||||
</HEAD><BODY>
|
|
||||||
<OBJECT type="text/site properties">
|
|
||||||
<param name="Window Styles" value="0x801227">
|
|
||||||
<param name="ImageType" value="Folder">
|
|
||||||
</OBJECT>
|
|
||||||
<UL>
|
|
||||||
'''
|
|
||||||
|
|
||||||
contents_footer = '''\
|
|
||||||
</UL></BODY></HTML>
|
|
||||||
'''
|
|
||||||
|
|
||||||
object_sitemap = '''\
|
|
||||||
<OBJECT type="text/sitemap">
|
|
||||||
<param name="Name" value="%s">
|
|
||||||
<param name="Local" value="%s">
|
|
||||||
</OBJECT>
|
|
||||||
'''
|
|
||||||
|
|
||||||
# List of words the full text search facility shouldn't index. This
|
|
||||||
# becomes file ARCH.stp. Note that this list must be pretty small!
|
|
||||||
# Different versions of the MS docs claim the file has a maximum size of
|
|
||||||
# 256 or 512 bytes (including \r\n at the end of each line).
|
|
||||||
# Note that "and", "or", "not" and "near" are operators in the search
|
|
||||||
# language, so no point indexing them even if we wanted to.
|
|
||||||
stop_list = '''
|
|
||||||
a and are as at
|
|
||||||
be but by
|
|
||||||
for
|
|
||||||
if in into is it
|
|
||||||
near no not
|
|
||||||
of on or
|
|
||||||
such
|
|
||||||
that the their then there these they this to
|
|
||||||
was will with
|
|
||||||
'''
|
|
||||||
|
|
||||||
# s is a string or None. If None or empty, return None. Else tack '.html'
|
|
||||||
# on to the end, unless it's already there.
|
|
||||||
def addhtml(s):
|
|
||||||
if s:
|
|
||||||
if not s.endswith('.html'):
|
|
||||||
s += '.html'
|
|
||||||
return s
|
|
||||||
|
|
||||||
# Convenience class to hold info about "a book" in HTMLHelp terms == a doc
|
|
||||||
# directory in Python terms.
|
|
||||||
class Book:
|
|
||||||
def __init__(self, directory, title, firstpage,
|
|
||||||
contentpage=None, indexpage=None):
|
|
||||||
self.directory = directory
|
|
||||||
self.title = title
|
|
||||||
self.firstpage = addhtml(firstpage)
|
|
||||||
self.contentpage = addhtml(contentpage)
|
|
||||||
self.indexpage = addhtml(indexpage)
|
|
||||||
|
|
||||||
# Library Doc list of books:
|
|
||||||
# each 'book' : (Dir, Title, First page, Content page, Index page)
|
|
||||||
supported_libraries = {
|
|
||||||
'2.2':
|
|
||||||
[
|
|
||||||
Book('.', 'Main page', 'index'),
|
|
||||||
Book('.', 'Global Module Index', 'modindex'),
|
|
||||||
Book('whatsnew', "What's New", 'index', 'contents'),
|
|
||||||
Book('tut','Tutorial','tut','node2'),
|
|
||||||
Book('lib','Library Reference','lib','contents','genindex'),
|
|
||||||
Book('ref','Language Reference','ref','contents','genindex'),
|
|
||||||
Book('mac','Macintosh Reference','mac','contents','genindex'),
|
|
||||||
Book('ext','Extending and Embedding','ext','contents'),
|
|
||||||
Book('api','Python/C API','api','contents','genindex'),
|
|
||||||
Book('doc','Documenting Python','doc','contents'),
|
|
||||||
Book('inst','Installing Python Modules', 'inst', 'index'),
|
|
||||||
Book('dist','Distributing Python Modules', 'dist', 'index'),
|
|
||||||
],
|
|
||||||
|
|
||||||
'2.1.1':
|
|
||||||
[
|
|
||||||
Book('.', 'Main page', 'index'),
|
|
||||||
Book('.', 'Global Module Index', 'modindex'),
|
|
||||||
Book('tut','Tutorial','tut','node2'),
|
|
||||||
Book('lib','Library Reference','lib','contents','genindex'),
|
|
||||||
Book('ref','Language Reference','ref','contents','genindex'),
|
|
||||||
Book('mac','Macintosh Reference','mac','contents','genindex'),
|
|
||||||
Book('ext','Extending and Embedding','ext','contents'),
|
|
||||||
Book('api','Python/C API','api','contents','genindex'),
|
|
||||||
Book('doc','Documenting Python','doc','contents'),
|
|
||||||
Book('inst','Installing Python Modules', 'inst', 'index'),
|
|
||||||
Book('dist','Distributing Python Modules', 'dist', 'index'),
|
|
||||||
],
|
|
||||||
|
|
||||||
'2.0.0':
|
|
||||||
[
|
|
||||||
Book('.', 'Global Module Index', 'modindex'),
|
|
||||||
Book('tut','Tutorial','tut','node2'),
|
|
||||||
Book('lib','Library Reference','lib','contents','genindex'),
|
|
||||||
Book('ref','Language Reference','ref','contents','genindex'),
|
|
||||||
Book('mac','Macintosh Reference','mac','contents','genindex'),
|
|
||||||
Book('ext','Extending and Embedding','ext','contents'),
|
|
||||||
Book('api','Python/C API','api','contents','genindex'),
|
|
||||||
Book('doc','Documenting Python','doc','contents'),
|
|
||||||
Book('inst','Installing Python Modules', 'inst', 'contents'),
|
|
||||||
Book('dist','Distributing Python Modules', 'dist', 'contents'),
|
|
||||||
],
|
|
||||||
|
|
||||||
# <dnagata@creo.com> Apr 17/99: library for 1.5.2 version:
|
|
||||||
# <hernan.foffani@iname.com> May 01/99: library for 1.5.2 (04/30/99):
|
|
||||||
'1.5.2':
|
|
||||||
[
|
|
||||||
Book('tut','Tutorial','tut','node2'),
|
|
||||||
Book('lib','Library Reference','lib','contents','genindex'),
|
|
||||||
Book('ref','Language Reference','ref','contents','genindex'),
|
|
||||||
Book('mac','Macintosh Reference','mac','contents','genindex'),
|
|
||||||
Book('ext','Extending and Embedding','ext','contents'),
|
|
||||||
Book('api','Python/C API','api','contents','genindex'),
|
|
||||||
Book('doc','Documenting Python','doc','contents')
|
|
||||||
],
|
|
||||||
|
|
||||||
# library for 1.5.1 version:
|
|
||||||
'1.5.1':
|
|
||||||
[
|
|
||||||
Book('tut','Tutorial','tut','contents'),
|
|
||||||
Book('lib','Library Reference','lib','contents','genindex'),
|
|
||||||
Book('ref','Language Reference','ref-1','ref-2','ref-11'),
|
|
||||||
Book('ext','Extending and Embedding','ext','contents'),
|
|
||||||
Book('api','Python/C API','api','contents','genindex')
|
|
||||||
],
|
|
||||||
|
|
||||||
# library for 1.5 version:
|
|
||||||
'1.5':
|
|
||||||
[
|
|
||||||
Book('tut','Tutorial','tut','node1'),
|
|
||||||
Book('lib','Library Reference','lib','node1','node268'),
|
|
||||||
Book('ref','Language Reference','ref-1','ref-2','ref-11'),
|
|
||||||
Book('ext','Extending and Embedding','ext','node1'),
|
|
||||||
Book('api','Python/C API','api','node1','node48')
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# AlmostNullWriter doesn't print anything; it just arranges to save the
|
|
||||||
# text sent to send_flowing_data(). This is used to capture the text
|
|
||||||
# between an anchor begin/end pair, e.g. for TOC entries.
|
|
||||||
|
|
||||||
class AlmostNullWriter(NullWriter):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
NullWriter.__init__(self)
|
|
||||||
self.saved_clear()
|
|
||||||
|
|
||||||
def send_flowing_data(self, data):
|
|
||||||
stripped = data.strip()
|
|
||||||
if stripped: # don't bother to save runs of whitespace
|
|
||||||
self.saved.append(stripped)
|
|
||||||
|
|
||||||
# Forget all saved text.
|
|
||||||
def saved_clear(self):
|
|
||||||
self.saved = []
|
|
||||||
|
|
||||||
# Return all saved text as a string.
|
|
||||||
def saved_get(self):
|
|
||||||
return ' '.join(self.saved)
|
|
||||||
|
|
||||||
class HelpHtmlParser(HTMLParser):
|
|
||||||
|
|
||||||
def __init__(self, formatter, path, output):
|
|
||||||
HTMLParser.__init__(self, formatter)
|
|
||||||
self.path = path # relative path
|
|
||||||
self.ft = output # output file
|
|
||||||
self.indent = 0 # number of tabs for pretty printing of files
|
|
||||||
self.proc = False # True when actively processing, else False
|
|
||||||
# (headers, footers, etc)
|
|
||||||
# XXX This shouldn't need to be a stack -- anchors shouldn't nest.
|
|
||||||
# XXX See SF bug <http://www.python.org/sf/546579>.
|
|
||||||
self.hrefstack = [] # stack of hrefs from anchor begins
|
|
||||||
|
|
||||||
def begin_group(self):
|
|
||||||
self.indent += 1
|
|
||||||
self.proc = True
|
|
||||||
|
|
||||||
def finish_group(self):
|
|
||||||
self.indent -= 1
|
|
||||||
# stop processing when back to top level
|
|
||||||
self.proc = self.indent > 0
|
|
||||||
|
|
||||||
def anchor_bgn(self, href, name, type):
|
|
||||||
if self.proc:
|
|
||||||
# XXX See SF bug <http://www.python.org/sf/546579>.
|
|
||||||
# XXX index.html for the 2.2.1 language reference manual contains
|
|
||||||
# XXX nested <a></a> tags in the entry for the section on blank
|
|
||||||
# XXX lines. We want to ignore the nested part completely.
|
|
||||||
if len(self.hrefstack) == 0:
|
|
||||||
self.saved_clear()
|
|
||||||
self.hrefstack.append(href)
|
|
||||||
|
|
||||||
def anchor_end(self):
|
|
||||||
if self.proc:
|
|
||||||
# XXX See XXX above.
|
|
||||||
if self.hrefstack:
|
|
||||||
title = cgi.escape(self.saved_get(), True)
|
|
||||||
path = self.path + '/' + self.hrefstack.pop()
|
|
||||||
self.tab(object_sitemap % (title, path))
|
|
||||||
|
|
||||||
def start_dl(self, atr_val):
|
|
||||||
self.begin_group()
|
|
||||||
|
|
||||||
def end_dl(self):
|
|
||||||
self.finish_group()
|
|
||||||
|
|
||||||
def do_dt(self, atr_val):
|
|
||||||
# no trailing newline on purpose!
|
|
||||||
self.tab("<LI>")
|
|
||||||
|
|
||||||
# Write text to output file.
|
|
||||||
def write(self, text):
|
|
||||||
self.ft.write(text)
|
|
||||||
|
|
||||||
# Write text to output file after indenting by self.indent tabs.
|
|
||||||
def tab(self, text=''):
|
|
||||||
self.write('\t' * self.indent)
|
|
||||||
if text:
|
|
||||||
self.write(text)
|
|
||||||
|
|
||||||
# Forget all saved text.
|
|
||||||
def saved_clear(self):
|
|
||||||
self.formatter.writer.saved_clear()
|
|
||||||
|
|
||||||
# Return all saved text as a string.
|
|
||||||
def saved_get(self):
|
|
||||||
return self.formatter.writer.saved_get()
|
|
||||||
|
|
||||||
class IdxHlpHtmlParser(HelpHtmlParser):
|
|
||||||
# nothing special here, seems enough with parent class
|
|
||||||
pass
|
|
||||||
|
|
||||||
class TocHlpHtmlParser(HelpHtmlParser):
|
|
||||||
|
|
||||||
def start_dl(self, atr_val):
|
|
||||||
self.begin_group()
|
|
||||||
self.tab('<UL>\n')
|
|
||||||
|
|
||||||
def end_dl(self):
|
|
||||||
self.finish_group()
|
|
||||||
self.tab('</UL>\n')
|
|
||||||
|
|
||||||
def start_ul(self, atr_val):
|
|
||||||
self.begin_group()
|
|
||||||
self.tab('<UL>\n')
|
|
||||||
|
|
||||||
def end_ul(self):
|
|
||||||
self.finish_group()
|
|
||||||
self.tab('</UL>\n')
|
|
||||||
|
|
||||||
def do_li(self, atr_val):
|
|
||||||
# no trailing newline on purpose!
|
|
||||||
self.tab("<LI>")
|
|
||||||
|
|
||||||
def index(path, indexpage, output):
|
|
||||||
parser = IdxHlpHtmlParser(AbstractFormatter(AlmostNullWriter()),
|
|
||||||
path, output)
|
|
||||||
f = open(path + '/' + indexpage)
|
|
||||||
parser.feed(f.read())
|
|
||||||
parser.close()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
def content(path, contentpage, output):
|
|
||||||
parser = TocHlpHtmlParser(AbstractFormatter(AlmostNullWriter()),
|
|
||||||
path, output)
|
|
||||||
f = open(path + '/' + contentpage)
|
|
||||||
parser.feed(f.read())
|
|
||||||
parser.close()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
def do_index(library, output):
|
|
||||||
output.write('<UL>\n')
|
|
||||||
for book in library:
|
|
||||||
print '\t', book.title, '-', book.indexpage
|
|
||||||
if book.indexpage:
|
|
||||||
index(book.directory, book.indexpage, output)
|
|
||||||
output.write('</UL>\n')
|
|
||||||
|
|
||||||
def do_content(library, version, output):
|
|
||||||
output.write(contents_header)
|
|
||||||
for book in library:
|
|
||||||
print '\t', book.title, '-', book.firstpage
|
|
||||||
path = book.directory + "/" + book.firstpage
|
|
||||||
output.write('<LI>')
|
|
||||||
output.write(object_sitemap % (book.title, path))
|
|
||||||
if book.contentpage:
|
|
||||||
content(book.directory, book.contentpage, output)
|
|
||||||
output.write(contents_footer)
|
|
||||||
|
|
||||||
# Fill in the [FILES] section of the project (.hhp) file.
|
|
||||||
# 'library' is the list of directory description tuples from
|
|
||||||
# supported_libraries for the version of the docs getting generated.
|
|
||||||
def do_project(library, output, arch, version):
|
|
||||||
output.write(project_template % locals())
|
|
||||||
pathseen = {}
|
|
||||||
for book in library:
|
|
||||||
directory = book.directory
|
|
||||||
path = directory + '\\%s\n'
|
|
||||||
for page in os.listdir(directory):
|
|
||||||
if page.endswith('.html') or page.endswith('.css'):
|
|
||||||
fullpath = path % page
|
|
||||||
if fullpath not in pathseen:
|
|
||||||
output.write(fullpath)
|
|
||||||
pathseen[fullpath] = True
|
|
||||||
|
|
||||||
def openfile(file):
|
|
||||||
try:
|
|
||||||
p = open(file, "w")
|
|
||||||
except IOError, msg:
|
|
||||||
print file, ":", msg
|
|
||||||
sys.exit(1)
|
|
||||||
return p
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
print usage_mode
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def do_it(args = None):
|
|
||||||
if not args:
|
|
||||||
args = sys.argv[1:]
|
|
||||||
|
|
||||||
if not args:
|
|
||||||
usage()
|
|
||||||
|
|
||||||
try:
|
|
||||||
optlist, args = getopt.getopt(args, 'ckpv:')
|
|
||||||
except getopt.error, msg:
|
|
||||||
print msg
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if not args or len(args) > 1:
|
|
||||||
usage()
|
|
||||||
arch = args[0]
|
|
||||||
|
|
||||||
version = None
|
|
||||||
for opt in optlist:
|
|
||||||
if opt[0] == '-v':
|
|
||||||
version = opt[1]
|
|
||||||
break
|
|
||||||
if not version:
|
|
||||||
usage()
|
|
||||||
|
|
||||||
library = supported_libraries[version]
|
|
||||||
|
|
||||||
if not (('-p','') in optlist):
|
|
||||||
fname = arch + '.stp'
|
|
||||||
f = openfile(fname)
|
|
||||||
print "Building stoplist", fname, "..."
|
|
||||||
words = stop_list.split()
|
|
||||||
words.sort()
|
|
||||||
for word in words:
|
|
||||||
print >> f, word
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
f = openfile(arch + '.hhp')
|
|
||||||
print "Building Project..."
|
|
||||||
do_project(library, f, arch, version)
|
|
||||||
if version == '2.0.0':
|
|
||||||
for image in os.listdir('icons'):
|
|
||||||
f.write('icons'+ '\\' + image + '\n')
|
|
||||||
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
if not (('-c','') in optlist):
|
|
||||||
f = openfile(arch + '.hhc')
|
|
||||||
print "Building Table of Content..."
|
|
||||||
do_content(library, version, f)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
if not (('-k','') in optlist):
|
|
||||||
f = openfile(arch + '.hhk')
|
|
||||||
print "Building Index..."
|
|
||||||
do_index(library, f)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
do_it()
|
|
@ -1,90 +0,0 @@
|
|||||||
#! /bin/sh
|
|
||||||
|
|
||||||
# Script to push docs from my development area to SourceForge, where the
|
|
||||||
# update-docs.sh script unpacks them into their final destination.
|
|
||||||
|
|
||||||
TARGETHOST=www.python.org
|
|
||||||
TARGETDIR=/usr/home/fdrake/tmp
|
|
||||||
|
|
||||||
TARGET="$TARGETHOST:$TARGETDIR"
|
|
||||||
|
|
||||||
ADDRESSES='python-dev@python.org doc-sig@python.org python-list@python.org'
|
|
||||||
|
|
||||||
VERSION=`echo '$Revision$' | sed 's/[$]Revision: \(.*\) [$]/\1/'`
|
|
||||||
EXTRA=`echo "$VERSION" | sed 's/^[0-9][0-9]*\.[0-9][0-9]*//'`
|
|
||||||
if [ "$EXTRA" ] ; then
|
|
||||||
DOCLABEL="maintenance"
|
|
||||||
DOCTYPE="maint"
|
|
||||||
else
|
|
||||||
DOCLABEL="development"
|
|
||||||
DOCTYPE="devel"
|
|
||||||
fi
|
|
||||||
|
|
||||||
EXPLANATION=''
|
|
||||||
ANNOUNCE=true
|
|
||||||
|
|
||||||
while [ "$#" -gt 0 ] ; do
|
|
||||||
case "$1" in
|
|
||||||
-m)
|
|
||||||
EXPLANATION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-q)
|
|
||||||
ANNOUNCE=false
|
|
||||||
shift 1
|
|
||||||
;;
|
|
||||||
-t)
|
|
||||||
DOCTYPE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-F)
|
|
||||||
EXPLANATION="`cat $2`"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
echo "Unknown option: $1" >&2
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [ "$1" ] ; then
|
|
||||||
if [ "$EXPLANATION" ] ; then
|
|
||||||
echo "Explanation may only be given once!" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
EXPLANATION="$1"
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
START="`pwd`"
|
|
||||||
MYDIR="`dirname $0`"
|
|
||||||
cd "$MYDIR"
|
|
||||||
MYDIR="`pwd`"
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# now in .../Doc/
|
|
||||||
make --no-print-directory bziphtml || exit $?
|
|
||||||
RELEASE=`grep '^RELEASE=' Makefile | sed 's|RELEASE=||'`
|
|
||||||
PACKAGE="html-$RELEASE.tar.bz2"
|
|
||||||
scp "$PACKAGE" tools/update-docs.sh $TARGET/ || exit $?
|
|
||||||
ssh "$TARGETHOST" tmp/update-docs.sh $DOCTYPE $PACKAGE '&&' rm tmp/update-docs.sh || exit $?
|
|
||||||
|
|
||||||
if $ANNOUNCE ; then
|
|
||||||
sendmail $ADDRESSES <<EOF
|
|
||||||
To: $ADDRESSES
|
|
||||||
From: "Fred L. Drake" <fdrake@acm.org>
|
|
||||||
Subject: [$DOCLABEL doc updates]
|
|
||||||
X-No-Archive: yes
|
|
||||||
|
|
||||||
The $DOCLABEL version of the documentation has been updated:
|
|
||||||
|
|
||||||
http://$TARGETHOST/dev/doc/$DOCTYPE/
|
|
||||||
|
|
||||||
$EXPLANATION
|
|
||||||
EOF
|
|
||||||
exit $?
|
|
||||||
fi
|
|
@ -1,920 +0,0 @@
|
|||||||
;;; py2texi.el -- Conversion of Python LaTeX documentation to Texinfo
|
|
||||||
|
|
||||||
;; Copyright (C) 1998, 1999, 2001, 2002 Milan Zamazal
|
|
||||||
|
|
||||||
;; Author: Milan Zamazal <pdm@zamazal.org>
|
|
||||||
;; Version: $Id$
|
|
||||||
;; Keywords: python
|
|
||||||
|
|
||||||
;; COPYRIGHT NOTICE
|
|
||||||
;;
|
|
||||||
;; This program is free software; you can redistribute it and/or modify it
|
|
||||||
;; under the terms of the GNU General Public License as published by the Free
|
|
||||||
;; Software Foundation; either version 2, or (at your option) any later
|
|
||||||
;; version.
|
|
||||||
;;
|
|
||||||
;; This program 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 General Public License
|
|
||||||
;; for more details.
|
|
||||||
;;
|
|
||||||
;; You can find the GNU General Public License at
|
|
||||||
;; http://www.gnu.org/copyleft/gpl.html
|
|
||||||
;; or you can write to the Free Software Foundation, Inc., 59 Temple Place,
|
|
||||||
;; Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; This is a Q&D hack for conversion of Python manuals to on-line help format.
|
|
||||||
;; I desperately needed usable online documenta for Python, so I wrote this.
|
|
||||||
;; The result code is ugly and need not contain complete information from
|
|
||||||
;; Python manuals. I apologize for my ignorance, especially ignorance to
|
|
||||||
;; python.sty. Improvements of this convertor are welcomed.
|
|
||||||
|
|
||||||
;; How to use it:
|
|
||||||
;; Load this file and apply `M-x py2texi'. You will be asked for name of a
|
|
||||||
;; file to be converted.
|
|
||||||
|
|
||||||
;; Where to find it:
|
|
||||||
;; New versions of this code might be found at
|
|
||||||
;; http://www.zamazal.org/software/python/py2texi/ .
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
|
|
||||||
(require 'texinfo)
|
|
||||||
(eval-when-compile
|
|
||||||
(require 'cl))
|
|
||||||
|
|
||||||
|
|
||||||
(defvar py2texi-python-version "2.2"
|
|
||||||
"What to substitute for the \\version macro.")
|
|
||||||
|
|
||||||
(defvar py2texi-python-short-version
|
|
||||||
(progn
|
|
||||||
(string-match "[0-9]+\\.[0-9]+" py2texi-python-version)
|
|
||||||
(match-string 0 py2texi-python-version))
|
|
||||||
"Short version number, usually set by the LaTeX commands.")
|
|
||||||
|
|
||||||
(defvar py2texi-texi-file-name nil
|
|
||||||
"If non-nil, that string is used as the name of the Texinfo file.
|
|
||||||
Otherwise a generated Texinfo file name is used.")
|
|
||||||
|
|
||||||
(defvar py2texi-info-file-name nil
|
|
||||||
"If non-nil, that string is used as the name of the Info file.
|
|
||||||
Otherwise a generated Info file name is used.")
|
|
||||||
|
|
||||||
(defvar py2texi-stop-on-problems nil
|
|
||||||
"*If non-nil, stop when you encouter soft problem.")
|
|
||||||
|
|
||||||
(defconst py2texi-environments
|
|
||||||
'(("abstract" 0 "@quotation" "@end quotation\n")
|
|
||||||
("center" 0 "" "")
|
|
||||||
("cfuncdesc" 3
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1 \\2(\\3)\n@findex \\2\n")
|
|
||||||
"@end table\n")
|
|
||||||
("cmemberdesc" 3
|
|
||||||
"\n@table @code\n@item \\2 \\3\n"
|
|
||||||
"@end table\n")
|
|
||||||
("classdesc" 2
|
|
||||||
(progn (setq obindex t)
|
|
||||||
"\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("classdesc*" 1
|
|
||||||
(progn (setq obindex t)
|
|
||||||
"\n@table @code\n@item \\1\n@obindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("csimplemacrodesc" 1
|
|
||||||
(progn (setq cindex t)
|
|
||||||
"\n@table @code\n@item \\1\n@cindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("ctypedesc" 1
|
|
||||||
(progn (setq cindex t)
|
|
||||||
"\n@table @code\n@item \\1\n@cindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("cvardesc" 2
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1 \\2\n@findex \\2\n")
|
|
||||||
"@end table\n")
|
|
||||||
("datadesc" 1
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1\n@findex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
|
|
||||||
("definitions" 0 "@table @dfn" "@end table\n")
|
|
||||||
("description" 0 "@table @samp" "@end table\n")
|
|
||||||
("displaymath" 0 "" "")
|
|
||||||
("document" 0
|
|
||||||
(concat "@defcodeindex mo\n"
|
|
||||||
"@defcodeindex ob\n"
|
|
||||||
"@titlepage\n"
|
|
||||||
(format "@title " title "\n")
|
|
||||||
(format "@author " author "\n")
|
|
||||||
"@page\n"
|
|
||||||
author-address
|
|
||||||
"@end titlepage\n"
|
|
||||||
"@node Top, , , (dir)\n")
|
|
||||||
(concat "@indices\n"
|
|
||||||
"@contents\n"
|
|
||||||
"@bye\n"))
|
|
||||||
("enumerate" 0 "@enumerate" "@end enumerate")
|
|
||||||
("excdesc" 1
|
|
||||||
(progn (setq obindex t)
|
|
||||||
"\n@table @code\n@item \\1\n@obindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("excclassdesc" 2
|
|
||||||
(progn (setq obindex t)
|
|
||||||
"\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("flushleft" 0 "" "")
|
|
||||||
("fulllineitems" 0 "\n@table @code\n" "@end table\n")
|
|
||||||
("funcdesc" 2
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
|
|
||||||
("itemize" 0 "@itemize @bullet" "@end itemize\n")
|
|
||||||
("list" 2 "\n@table @code\n" "@end table\n")
|
|
||||||
("longtableii" 4 (concat "@multitable @columnfractions .5 .5\n"
|
|
||||||
"@item \\3 @tab \\4\n"
|
|
||||||
"@item ------- @tab ------ \n")
|
|
||||||
"@end multitable\n")
|
|
||||||
("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
|
|
||||||
"@item \\3 @tab \\4 @tab \\5\n"
|
|
||||||
"@item ------- @tab ------ @tab ------\n")
|
|
||||||
"@end multitable\n")
|
|
||||||
("memberdesc" 1
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1\n@findex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
|
|
||||||
("methoddesc" 2
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
|
|
||||||
("notice" 0 "@emph{Notice:} " "")
|
|
||||||
("opcodedesc" 2
|
|
||||||
(progn (setq findex t)
|
|
||||||
"\n@table @code\n@item \\1 \\2\n@findex \\1\n")
|
|
||||||
"@end table\n")
|
|
||||||
("productionlist" 0 "\n@table @code\n" "@end table\n")
|
|
||||||
("quotation" 0 "@quotation" "@end quotation")
|
|
||||||
("seealso" 0 "See also:\n@table @emph\n" "@end table\n")
|
|
||||||
("seealso*" 0 "@table @emph\n" "@end table\n")
|
|
||||||
("sloppypar" 0 "" "")
|
|
||||||
("small" 0 "" "")
|
|
||||||
("tableii" 4 (concat "@multitable @columnfractions .5 .5\n"
|
|
||||||
"@item \\3 @tab \\4\n"
|
|
||||||
"@item ------- @tab ------ \n")
|
|
||||||
"@end multitable\n")
|
|
||||||
("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
|
|
||||||
"@item \\3 @tab \\4 @tab \\5\n"
|
|
||||||
"@item ------- @tab ------ @tab ------\n")
|
|
||||||
"@end multitable\n")
|
|
||||||
("tableiv" 6 (concat
|
|
||||||
"@multitable @columnfractions .25 .25 .25 .25\n"
|
|
||||||
"@item \\3 @tab \\4 @tab \\5 @tab \\6\n"
|
|
||||||
"@item ------- @tab ------- @tab ------- @tab -------\n")
|
|
||||||
"@end multitable\n")
|
|
||||||
("tablev" 7 (concat
|
|
||||||
"@multitable @columnfractions .20 .20 .20 .20 .20\n"
|
|
||||||
"@item \\3 @tab \\4 @tab \\5 @tab \\6 @tab \\7\n"
|
|
||||||
"@item ------- @tab ------- @tab ------- @tab ------- @tab -------\n")
|
|
||||||
"@end multitable\n"))
|
|
||||||
"Associative list defining substitutions for environments.
|
|
||||||
Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where:
|
|
||||||
- ENVIRONMENT is LaTeX environment name
|
|
||||||
- ARGNUM is number of (required) macro arguments
|
|
||||||
- BEGIN is substitution for \begin{ENVIRONMENT}
|
|
||||||
- END is substitution for \end{ENVIRONMENT}
|
|
||||||
Both BEGIN and END are evaled. Moreover, you can reference arguments through
|
|
||||||
\N regular expression notation in strings of BEGIN.")
|
|
||||||
|
|
||||||
(defconst py2texi-commands
|
|
||||||
'(("ABC" 0 "ABC")
|
|
||||||
("appendix" 0 (progn (setq appendix t) ""))
|
|
||||||
("ASCII" 0 "ASCII")
|
|
||||||
("author" 1 (progn (setq author (match-string 1 string)) ""))
|
|
||||||
("authoraddress" 1
|
|
||||||
(progn (setq author-address (match-string 1 string)) ""))
|
|
||||||
("b" 1 "@w{\\1}")
|
|
||||||
("bf" 0 "@destroy")
|
|
||||||
("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}"))
|
|
||||||
("C" 0 "C")
|
|
||||||
("c" 0 "@,")
|
|
||||||
("catcode" 0 "")
|
|
||||||
("cdata" 1 "@code{\\1}")
|
|
||||||
("centerline" 1 "@center \\1")
|
|
||||||
("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
|
|
||||||
("cfunction" 1 "@code{\\1}")
|
|
||||||
("chapter" 1 (format "@node \\1\n@%s \\1\n"
|
|
||||||
(if appendix "appendix" "chapter")))
|
|
||||||
("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
|
|
||||||
("character" 1 "@samp{\\1}")
|
|
||||||
("citetitle" 1 "@ref{Top,,,\\1}")
|
|
||||||
("class" 1 "@code{\\1}")
|
|
||||||
("cmemberline" 3 "@itemx \\2 \\3\n")
|
|
||||||
("code" 1 "@code{\\1}")
|
|
||||||
("command" 1 "@command{\\1}")
|
|
||||||
("constant" 1 "@code{\\1}")
|
|
||||||
("copyright" 1 "@copyright{}")
|
|
||||||
("Cpp" 0 "C++")
|
|
||||||
("csimplemacro" 1 "@code{\\1}")
|
|
||||||
("ctype" 1 "@code{\\1}")
|
|
||||||
("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n"))
|
|
||||||
("date" 1 "\\1")
|
|
||||||
("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}"))
|
|
||||||
("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}")
|
|
||||||
("dfn" 1 "@dfn{\\1}")
|
|
||||||
("documentclass" 1 py2texi-magic)
|
|
||||||
("e" 0 "@backslash{}")
|
|
||||||
("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex")))
|
|
||||||
("EOF" 0 "@code{EOF}")
|
|
||||||
("email" 1 "@email{\\1}")
|
|
||||||
("emph" 1 "@emph{\\1}")
|
|
||||||
("envvar" 1 "@samp{\\1}")
|
|
||||||
("exception" 1 "@code{\\1}")
|
|
||||||
("exindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
|
|
||||||
("fi" 0 (concat "@end " last-if))
|
|
||||||
("file" 1 "@file{\\1}")
|
|
||||||
("filevar" 1 "@file{@var{\\1}}")
|
|
||||||
("footnote" 1 "@footnote{\\1}")
|
|
||||||
("frac" 0 "")
|
|
||||||
("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1"))
|
|
||||||
("funclineni" 2 "@item \\1 \\2")
|
|
||||||
("function" 1 "@code{\\1}")
|
|
||||||
("grammartoken" 1 "@code{\\1}")
|
|
||||||
("hline" 0 "")
|
|
||||||
("ifhtml" 0 (concat "@" (setq last-if "ifinfo")))
|
|
||||||
("iftexi" 0 (concat "@" (setq last-if "ifinfo")))
|
|
||||||
("index" 1 (progn (setq cindex t) "@cindex{\\1}"))
|
|
||||||
("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}"))
|
|
||||||
("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}"))
|
|
||||||
("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}"))
|
|
||||||
("infinity" 0 "@emph{infinity}")
|
|
||||||
("it" 0 "@destroy")
|
|
||||||
("kbd" 1 "@key{\\1}")
|
|
||||||
("keyword" 1 "@code{\\1}")
|
|
||||||
("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
|
|
||||||
("label" 1 "@label{\\1}")
|
|
||||||
("Large" 0 "")
|
|
||||||
("LaTeX" 0 "La@TeX{}")
|
|
||||||
("large" 0 "")
|
|
||||||
("ldots" 0 "@dots{}")
|
|
||||||
("leftline" 1 "\\1")
|
|
||||||
("lineii" 2 "@item \\1 @tab \\2")
|
|
||||||
("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
|
|
||||||
("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
|
|
||||||
("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
|
|
||||||
("localmoduletable" 0 "")
|
|
||||||
("longprogramopt" 1 "@option{--\\1}")
|
|
||||||
("mailheader" 1 "@code{\\1}")
|
|
||||||
("makeindex" 0 "")
|
|
||||||
("makemodindex" 0 "")
|
|
||||||
("maketitle" 0 (concat "@top " title "\n"))
|
|
||||||
("makevar" 1 "@code{\\1}")
|
|
||||||
("manpage" 2 "@samp{\\1(\\2)}")
|
|
||||||
("mbox" 1 "@w{\\1}")
|
|
||||||
("member" 1 "@code{\\1}")
|
|
||||||
("memberline" 1 "@item \\1\n@findex \\1\n")
|
|
||||||
("menuselection" 1 "@samp{\\1}")
|
|
||||||
("method" 1 "@code{\\1}")
|
|
||||||
("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n"))
|
|
||||||
("methodlineni" 2 "@item \\1(\\2)\n")
|
|
||||||
("mimetype" 1 "@samp{\\1}")
|
|
||||||
("module" 1 "@samp{\\1}")
|
|
||||||
("moduleauthor" 2 "")
|
|
||||||
("modulesynopsis" 1 "\\1")
|
|
||||||
("moreargs" 0 "@dots{}")
|
|
||||||
("n" 0 "@backslash{}n")
|
|
||||||
("newcommand" 2 "")
|
|
||||||
("newsgroup" 1 "@samp{\\1}")
|
|
||||||
("nodename" 1
|
|
||||||
(save-excursion
|
|
||||||
(save-match-data
|
|
||||||
(re-search-backward "^@node "))
|
|
||||||
(delete-region (point) (save-excursion (end-of-line) (point)))
|
|
||||||
(insert "@node " (match-string 1 string))
|
|
||||||
""))
|
|
||||||
("noindent" 0 "@noindent ")
|
|
||||||
("note" 1 "@emph{Note:} \\1")
|
|
||||||
("NULL" 0 "@code{NULL}")
|
|
||||||
("obindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
|
|
||||||
("opindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
|
|
||||||
("option" 1 "@option{\\1}")
|
|
||||||
("optional" 1 "[\\1]")
|
|
||||||
("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n"))
|
|
||||||
("pi" 0 "pi")
|
|
||||||
("platform" 1 "")
|
|
||||||
("plusminus" 0 "+-")
|
|
||||||
("POSIX" 0 "POSIX")
|
|
||||||
("production" 2 "@item \\1 \\2")
|
|
||||||
("productioncont" 1 "@item @w{} \\1")
|
|
||||||
("program" 1 "@command{\\1}")
|
|
||||||
("programopt" 1 "@option{\\1}")
|
|
||||||
("protect" 0 "")
|
|
||||||
("pytype" 1 "@code{\\1}")
|
|
||||||
("ref" 1 "@ref{\\1}")
|
|
||||||
("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
|
|
||||||
("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
|
|
||||||
("refmodule" 1 "@samp{\\1}")
|
|
||||||
("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
|
|
||||||
("regexp" 1 "\"\\1\"")
|
|
||||||
("release" 1
|
|
||||||
(progn (setq py2texi-python-version (match-string 1 string)) ""))
|
|
||||||
("renewcommand" 2 "")
|
|
||||||
("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n"))
|
|
||||||
("rm" 0 "@destroy")
|
|
||||||
("samp" 1 "@samp{\\1}")
|
|
||||||
("section" 1 (let ((str (match-string 1 string)))
|
|
||||||
(save-match-data
|
|
||||||
(if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
|
|
||||||
str)
|
|
||||||
(format
|
|
||||||
"@node %s\n@section %s\n"
|
|
||||||
(py2texi-backslash-quote (match-string 1 str))
|
|
||||||
(py2texi-backslash-quote (match-string 2 str)))
|
|
||||||
"@node \\1\n@section \\1\n"))))
|
|
||||||
("sectionauthor" 2 "")
|
|
||||||
("seemodule" 2 "@ref{\\1} \\2")
|
|
||||||
("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
|
|
||||||
("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
|
|
||||||
("seetext" 1 "\\1")
|
|
||||||
("seetitle" 1 "@cite{\\1}")
|
|
||||||
("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
|
|
||||||
("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1"))
|
|
||||||
("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo "")))
|
|
||||||
("setshortversion" 1
|
|
||||||
(progn (setq py2texi-python-short-version (match-string 1 string)) ""))
|
|
||||||
("shortversion" 0 py2texi-python-short-version)
|
|
||||||
("sqrt" 0 "")
|
|
||||||
("stindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
|
|
||||||
("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
|
|
||||||
("strong" 1 "@strong{\\1}")
|
|
||||||
("sub" 0 "/")
|
|
||||||
("subsection" 1 "@node \\1\n@subsection \\1\n")
|
|
||||||
("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
|
|
||||||
("sum" 0 "")
|
|
||||||
("tableofcontents" 0 "")
|
|
||||||
("term" 1 "@item \\1")
|
|
||||||
("textasciitilde" 0 "~")
|
|
||||||
("textasciicircum" 0 "^")
|
|
||||||
("textbackslash" 0 "@backslash{}")
|
|
||||||
("textgreater" 0 ">")
|
|
||||||
("textless" 0 "<")
|
|
||||||
("textrm" 1 "\\1")
|
|
||||||
("texttt" 1 "@code{\\1}")
|
|
||||||
("textunderscore" 0 "_")
|
|
||||||
("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1"))
|
|
||||||
("today" 0 "@today{}")
|
|
||||||
("token" 1 "@code{\\1}")
|
|
||||||
("tt" 0 "@destroy")
|
|
||||||
("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
|
|
||||||
("u" 0 "@backslash{}u")
|
|
||||||
("ulink" 2 "\\1")
|
|
||||||
("UNIX" 0 "UNIX")
|
|
||||||
("unspecified" 0 "@dots{}")
|
|
||||||
("url" 1 "@url{\\1}")
|
|
||||||
("usepackage" 1 "")
|
|
||||||
("var" 1 "@var{\\1}")
|
|
||||||
("verbatiminput" 1 "@code{\\1}")
|
|
||||||
("version" 0 py2texi-python-version)
|
|
||||||
("versionadded" 1 "@emph{Added in Python version \\1}")
|
|
||||||
("versionchanged" 1 "@emph{Changed in Python version \\1}")
|
|
||||||
("vskip" 1 "")
|
|
||||||
("vspace" 1 "")
|
|
||||||
("warning" 1 "@emph{\\1}")
|
|
||||||
("withsubitem" 2 "\\2")
|
|
||||||
("XXX" 1 "@strong{\\1}"))
|
|
||||||
"Associative list of command substitutions.
|
|
||||||
Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
|
|
||||||
- COMMAND is LaTeX command name
|
|
||||||
- ARGNUM is number of (required) command arguments
|
|
||||||
- SUBSTITUTION substitution for the command. It is evaled and you can
|
|
||||||
reference command arguments through the \\N regexp notation in strings.")
|
|
||||||
|
|
||||||
(defvar py2texi-magic "@documentclass\n"
|
|
||||||
"\"Magic\" string for auxiliary insertion at the beginning of document.")
|
|
||||||
|
|
||||||
(defvar py2texi-dirs '("./" "../texinputs/")
|
|
||||||
"Where to search LaTeX input files.")
|
|
||||||
|
|
||||||
(defvar py2texi-buffer "*py2texi*"
|
|
||||||
"The name of a buffer where Texinfo is generated.")
|
|
||||||
|
|
||||||
(defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version))
|
|
||||||
"Running under XEmacs?")
|
|
||||||
|
|
||||||
|
|
||||||
(defmacro py2texi-search (regexp &rest body)
|
|
||||||
`(progn
|
|
||||||
(goto-char (point-min))
|
|
||||||
(while (re-search-forward ,regexp nil t)
|
|
||||||
,@body)))
|
|
||||||
|
|
||||||
(defmacro py2texi-search-safe (regexp &rest body)
|
|
||||||
`(py2texi-search ,regexp
|
|
||||||
(unless (py2texi-protected)
|
|
||||||
,@body)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-message (message)
|
|
||||||
"Report message and stop if `py2texi-stop-on-problems' is non-nil."
|
|
||||||
(if py2texi-stop-on-problems
|
|
||||||
(error message)
|
|
||||||
(message message)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-backslash-quote (string)
|
|
||||||
"Double backslahes in STRING."
|
|
||||||
(let ((i 0))
|
|
||||||
(save-match-data
|
|
||||||
(while (setq i (string-match "\\\\" string i))
|
|
||||||
(setq string (replace-match "\\\\\\\\" t nil string))
|
|
||||||
(setq i (+ i 2))))
|
|
||||||
string))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi (file)
|
|
||||||
"Convert Python LaTeX documentation FILE to Texinfo."
|
|
||||||
(interactive "fFile to convert: ")
|
|
||||||
(switch-to-buffer (get-buffer-create py2texi-buffer))
|
|
||||||
(erase-buffer)
|
|
||||||
(insert-file file)
|
|
||||||
(let ((case-fold-search nil)
|
|
||||||
(title "")
|
|
||||||
(author "")
|
|
||||||
(author-address "")
|
|
||||||
(appendix nil)
|
|
||||||
(findex nil)
|
|
||||||
(obindex nil)
|
|
||||||
(cindex nil)
|
|
||||||
(moindex nil)
|
|
||||||
last-if)
|
|
||||||
(py2texi-process-verbatims)
|
|
||||||
(py2texi-process-comments)
|
|
||||||
(py2texi-process-includes)
|
|
||||||
(py2texi-process-funnyas)
|
|
||||||
(py2texi-process-environments)
|
|
||||||
(py2texi-process-commands)
|
|
||||||
(py2texi-fix-indentation)
|
|
||||||
(py2texi-fix-nodes)
|
|
||||||
(py2texi-fix-references)
|
|
||||||
(py2texi-fix-indices)
|
|
||||||
(py2texi-process-simple-commands)
|
|
||||||
(py2texi-fix-fonts)
|
|
||||||
(py2texi-fix-braces)
|
|
||||||
(py2texi-fix-backslashes)
|
|
||||||
(py2texi-destroy-empties)
|
|
||||||
(py2texi-fix-newlines)
|
|
||||||
(py2texi-adjust-level))
|
|
||||||
(let* ((texi-file-name (or py2texi-texi-file-name
|
|
||||||
(py2texi-texi-file-name file)))
|
|
||||||
(info-file-name (or py2texi-info-file-name
|
|
||||||
(py2texi-info-file-name texi-file-name))))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(when (looking-at py2texi-magic)
|
|
||||||
(delete-region (point) (progn (beginning-of-line 2) (point)))
|
|
||||||
(insert "\\input texinfo @c -*-texinfo-*-\n")
|
|
||||||
(insert "@setfilename " info-file-name))
|
|
||||||
(when (re-search-forward "@chapter" nil t)
|
|
||||||
(texinfo-all-menus-update t))
|
|
||||||
(goto-char (point-min))
|
|
||||||
(write-file texi-file-name)
|
|
||||||
(message (format "You can apply `makeinfo %s' now." texi-file-name))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-texi-file-name (filename)
|
|
||||||
"Generate name of Texinfo file from original file name FILENAME."
|
|
||||||
(concat filename
|
|
||||||
(if (string-match "\\.tex$" filename) "i" ".texi")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-info-file-name (filename)
|
|
||||||
"Generate name of info file from original file name FILENAME."
|
|
||||||
(setq filename (expand-file-name filename))
|
|
||||||
(let ((directory (file-name-directory filename))
|
|
||||||
(basename (file-name-nondirectory filename)))
|
|
||||||
(concat directory "python-"
|
|
||||||
(substring basename 0 (- (length basename) 4)) "info")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-verbatims ()
|
|
||||||
"Process and protect verbatim environments."
|
|
||||||
(let (delimiter
|
|
||||||
beg
|
|
||||||
end)
|
|
||||||
(py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
|
|
||||||
(replace-match "@example")
|
|
||||||
(setq beg (copy-marker (point) nil))
|
|
||||||
(re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
|
|
||||||
(setq end (copy-marker (match-beginning 0) nil))
|
|
||||||
(replace-match "@end example")
|
|
||||||
(py2texi-texinfo-escape beg end)
|
|
||||||
(put-text-property (- beg (length "@example"))
|
|
||||||
(+ end (length "@end example"))
|
|
||||||
'py2texi-protected t))
|
|
||||||
(py2texi-search-safe "\\\\verb\\([^a-z]\\)"
|
|
||||||
(setq delimiter (match-string 1))
|
|
||||||
(replace-match "@code{")
|
|
||||||
(setq beg (copy-marker (point) nil))
|
|
||||||
(re-search-forward (regexp-quote delimiter))
|
|
||||||
(setq end (copy-marker (match-beginning 0) nil))
|
|
||||||
(replace-match "}")
|
|
||||||
(put-text-property (- beg (length "@code{")) (+ end (length "}"))
|
|
||||||
'py2texi-protected t)
|
|
||||||
(py2texi-texinfo-escape beg end))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-comments ()
|
|
||||||
"Remove comments."
|
|
||||||
(let (point)
|
|
||||||
(py2texi-search-safe "%"
|
|
||||||
(setq point (point))
|
|
||||||
(when (save-excursion
|
|
||||||
(re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t))
|
|
||||||
(delete-region (1- point)
|
|
||||||
(save-excursion (beginning-of-line 2) (point)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-includes ()
|
|
||||||
"Include LaTeX input files.
|
|
||||||
Do not include .ind files."
|
|
||||||
(let ((path (file-name-directory file))
|
|
||||||
filename
|
|
||||||
dirs
|
|
||||||
includefile)
|
|
||||||
(py2texi-search-safe "\\\\input{\\([^}]+\\)}"
|
|
||||||
(setq filename (match-string 1))
|
|
||||||
(unless (save-match-data (string-match "\\.tex$" filename))
|
|
||||||
(setq filename (concat filename ".tex")))
|
|
||||||
(setq includefile (save-match-data
|
|
||||||
(string-match "\\.ind\\.tex$" filename)))
|
|
||||||
(setq dirs py2texi-dirs)
|
|
||||||
(while (and (not includefile) dirs)
|
|
||||||
(setq includefile (concat path (car dirs) filename))
|
|
||||||
(unless (file-exists-p includefile)
|
|
||||||
(setq includefile nil)
|
|
||||||
(setq dirs (cdr dirs))))
|
|
||||||
(if includefile
|
|
||||||
(save-restriction
|
|
||||||
(narrow-to-region (match-beginning 0) (match-end 0))
|
|
||||||
(delete-region (point-min) (point-max))
|
|
||||||
(when (stringp includefile)
|
|
||||||
(insert-file-contents includefile)
|
|
||||||
(goto-char (point-min))
|
|
||||||
(insert "\n")
|
|
||||||
(py2texi-process-verbatims)
|
|
||||||
(py2texi-process-comments)
|
|
||||||
(py2texi-process-includes)))
|
|
||||||
(replace-match (format "\\\\emph{Included file %s}" filename))
|
|
||||||
(py2texi-message (format "Input file %s not found" filename))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-funnyas ()
|
|
||||||
"Convert @s."
|
|
||||||
(py2texi-search-safe "@"
|
|
||||||
(replace-match "@@")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-environments ()
|
|
||||||
"Process LaTeX environments."
|
|
||||||
(let ((stack ())
|
|
||||||
kind
|
|
||||||
environment
|
|
||||||
parameter
|
|
||||||
arguments
|
|
||||||
n
|
|
||||||
string
|
|
||||||
description)
|
|
||||||
(py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
|
|
||||||
"\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
|
|
||||||
(setq kind (match-string 1)
|
|
||||||
environment (match-string 3)
|
|
||||||
parameter (match-string 4))
|
|
||||||
(replace-match "")
|
|
||||||
(cond
|
|
||||||
((string= kind "begin")
|
|
||||||
(setq description (assoc environment py2texi-environments))
|
|
||||||
(if description
|
|
||||||
(progn
|
|
||||||
(setq n (cadr description))
|
|
||||||
(setq description (cddr description))
|
|
||||||
(setq string (py2texi-tex-arguments n))
|
|
||||||
(string-match (py2texi-regexp n) string)
|
|
||||||
; incorrect but sufficient
|
|
||||||
(insert (replace-match (eval (car description))
|
|
||||||
t nil string))
|
|
||||||
(setq stack (cons (cadr description) stack)))
|
|
||||||
(py2texi-message (format "Unknown environment: %s" environment))
|
|
||||||
(setq stack (cons "" stack))))
|
|
||||||
((string= kind "end")
|
|
||||||
(insert (eval (car stack)))
|
|
||||||
(setq stack (cdr stack)))
|
|
||||||
((string= kind "item")
|
|
||||||
(insert "\n@item " (or parameter "") "\n"))))
|
|
||||||
(when stack
|
|
||||||
(py2texi-message (format "Unclosed environment: %s" (car stack))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-commands ()
|
|
||||||
"Process LaTeX commands."
|
|
||||||
(let (done
|
|
||||||
command
|
|
||||||
command-info
|
|
||||||
string
|
|
||||||
n)
|
|
||||||
(while (not done)
|
|
||||||
(setq done t)
|
|
||||||
(py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
|
|
||||||
(setq command (match-string 1))
|
|
||||||
(setq command-info (assoc command py2texi-commands))
|
|
||||||
(if command-info
|
|
||||||
(progn
|
|
||||||
(setq done nil)
|
|
||||||
(replace-match "")
|
|
||||||
(setq command-info (cdr command-info))
|
|
||||||
(setq n (car command-info))
|
|
||||||
(setq string (py2texi-tex-arguments n))
|
|
||||||
(string-match (py2texi-regexp n) string)
|
|
||||||
; incorrect but sufficient
|
|
||||||
(insert (replace-match (eval (cadr command-info))
|
|
||||||
t nil string)))
|
|
||||||
(py2texi-message (format "Unknown command: %s (not processed)"
|
|
||||||
command)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-argument-pattern (count)
|
|
||||||
(let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
|
|
||||||
(if (<= count 0)
|
|
||||||
filler
|
|
||||||
(concat filler "\\(?:{"
|
|
||||||
(py2texi-argument-pattern (1- count))
|
|
||||||
"}" filler "\\)*" filler))))
|
|
||||||
(defconst py2texi-tex-argument
|
|
||||||
(concat
|
|
||||||
"{\\("
|
|
||||||
(py2texi-argument-pattern 10) ;really at least 10!
|
|
||||||
"\\)}[ \t%@c\n]*")
|
|
||||||
"Regexp describing LaTeX command argument including argument separators.")
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-regexp (n)
|
|
||||||
"Make regexp matching N LaTeX command arguments."
|
|
||||||
(if (= n 0)
|
|
||||||
""
|
|
||||||
(let ((regexp "^[^{]*"))
|
|
||||||
(while (> n 0)
|
|
||||||
(setq regexp (concat regexp py2texi-tex-argument))
|
|
||||||
(setq n (1- n)))
|
|
||||||
regexp)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-tex-arguments (n)
|
|
||||||
"Remove N LaTeX command arguments and return them as a string."
|
|
||||||
(let ((point (point))
|
|
||||||
(i 0)
|
|
||||||
result
|
|
||||||
match)
|
|
||||||
(if (= n 0)
|
|
||||||
(progn
|
|
||||||
(when (re-search-forward "\\=\\({}\\| *\\)" nil t)
|
|
||||||
(replace-match ""))
|
|
||||||
"")
|
|
||||||
(while (> n 0)
|
|
||||||
(unless (re-search-forward
|
|
||||||
"\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t)
|
|
||||||
(debug))
|
|
||||||
(if (string= (match-string 3) "{")
|
|
||||||
(setq i (1+ i))
|
|
||||||
(setq i (1- i))
|
|
||||||
(when (<= i 0)
|
|
||||||
(setq n (1- n)))))
|
|
||||||
(setq result (buffer-substring-no-properties point (point)))
|
|
||||||
(while (string-match "\n[ \t]*" result)
|
|
||||||
(setq result (replace-match " " t nil result)))
|
|
||||||
(delete-region point (point))
|
|
||||||
result)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-process-simple-commands ()
|
|
||||||
"Replace single character LaTeX commands."
|
|
||||||
(let (char)
|
|
||||||
(py2texi-search-safe "\\\\\\([^a-z]\\)"
|
|
||||||
(setq char (match-string 1))
|
|
||||||
(replace-match (format "%s%s"
|
|
||||||
(if (or (string= char "{")
|
|
||||||
(string= char "}")
|
|
||||||
(string= char " "))
|
|
||||||
"@"
|
|
||||||
"")
|
|
||||||
(if (string= char "\\")
|
|
||||||
"\\\\"
|
|
||||||
char))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-indentation ()
|
|
||||||
"Remove white space at the beginning of lines."
|
|
||||||
(py2texi-search-safe "^[ \t]+"
|
|
||||||
(replace-match "")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-nodes ()
|
|
||||||
"Remove unwanted characters from nodes and make nodes unique."
|
|
||||||
(let ((nodes (make-hash-table :test 'equal))
|
|
||||||
id
|
|
||||||
counter
|
|
||||||
string
|
|
||||||
label
|
|
||||||
index)
|
|
||||||
(py2texi-search "^@node +\\(.*\\)$"
|
|
||||||
(setq string (match-string 1))
|
|
||||||
(if py2texi-xemacs
|
|
||||||
(replace-match "@node " t)
|
|
||||||
(replace-match "" t nil nil 1))
|
|
||||||
(while (string-match "@label{[^}]*}" string)
|
|
||||||
(setq label (match-string 0 string))
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(while (string-match "@..?index{[^}]*}" string)
|
|
||||||
(setq index (match-string 0 string))
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string)
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(while (string-match " -- " string)
|
|
||||||
(setq string (replace-match " - " t nil string)))
|
|
||||||
(while (string-match "\\." string)
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(when (string-match " +$" string)
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string)
|
|
||||||
(setq string (replace-match "" t nil string)))
|
|
||||||
(string-match "^[^,]+" string)
|
|
||||||
(setq id (match-string 0 string))
|
|
||||||
(setq counter (gethash id nodes))
|
|
||||||
(if counter
|
|
||||||
(progn
|
|
||||||
(setq counter (1+ counter))
|
|
||||||
(setq string (replace-match (format "\\& %d" counter)
|
|
||||||
t nil string)))
|
|
||||||
(setq counter 1))
|
|
||||||
(setf (gethash id nodes) counter)
|
|
||||||
(insert string)
|
|
||||||
(beginning-of-line 3)
|
|
||||||
(when label
|
|
||||||
(insert label "\n"))
|
|
||||||
(when index
|
|
||||||
(insert index "\n")))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-references ()
|
|
||||||
"Process labels and make references to point to appropriate nodes."
|
|
||||||
(let ((labels ())
|
|
||||||
node)
|
|
||||||
(py2texi-search-safe "@label{\\([^}]*\\)}"
|
|
||||||
(setq node (save-excursion
|
|
||||||
(save-match-data
|
|
||||||
(and (re-search-backward "@node +\\([^,\n]+\\)" nil t)
|
|
||||||
(match-string 1)))))
|
|
||||||
(when node
|
|
||||||
(setq labels (cons (cons (match-string 1) node) labels)))
|
|
||||||
(replace-match ""))
|
|
||||||
(py2texi-search-safe "@ref{\\([^}]*\\)}"
|
|
||||||
(setq node (assoc (match-string 1) labels))
|
|
||||||
(replace-match "")
|
|
||||||
(when node
|
|
||||||
(insert (format "@ref{%s}" (cdr node)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-indices ()
|
|
||||||
"Remove unwanted characters from @*index commands and create final indices."
|
|
||||||
(py2texi-search-safe "@..?index\\>[^\n]*\\(\\)\n"
|
|
||||||
(replace-match "" t nil nil 1))
|
|
||||||
(py2texi-search-safe "@..?index\\>[^\n]*\\(\\)"
|
|
||||||
(replace-match "\n" t nil nil 1))
|
|
||||||
(py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
|
|
||||||
(replace-match " " t nil nil 1)
|
|
||||||
(replace-match "" t nil nil 3)
|
|
||||||
(let ((string (match-string 2)))
|
|
||||||
(save-match-data
|
|
||||||
(while (string-match "@[a-z]+{" string)
|
|
||||||
(setq string (replace-match "" nil nil string)))
|
|
||||||
(while (string-match "{" string)
|
|
||||||
(setq string (replace-match "" nil nil string))))
|
|
||||||
(replace-match string t t nil 2)))
|
|
||||||
(py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
|
|
||||||
(replace-match "" t nil nil 1)
|
|
||||||
(goto-char (match-beginning 0)))
|
|
||||||
(py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
|
|
||||||
(replace-match "\n" t nil nil 1))
|
|
||||||
(goto-char (point-max))
|
|
||||||
(re-search-backward "@indices")
|
|
||||||
(replace-match "")
|
|
||||||
(insert (if moindex
|
|
||||||
(concat "@node Module Index\n"
|
|
||||||
"@unnumbered Module Index\n"
|
|
||||||
"@printindex mo\n")
|
|
||||||
"")
|
|
||||||
(if obindex
|
|
||||||
(concat "@node Class-Exception-Object Index\n"
|
|
||||||
"@unnumbered Class, Exception, and Object Index\n"
|
|
||||||
"@printindex ob\n")
|
|
||||||
"")
|
|
||||||
(if findex
|
|
||||||
(concat "@node Function-Method-Variable Index\n"
|
|
||||||
"@unnumbered Function, Method, and Variable Index\n"
|
|
||||||
"@printindex fn\n")
|
|
||||||
"")
|
|
||||||
(if cindex
|
|
||||||
(concat "@node Miscellaneous Index\n"
|
|
||||||
"@unnumbered Miscellaneous Index\n"
|
|
||||||
"@printindex cp\n")
|
|
||||||
"")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-backslashes ()
|
|
||||||
"Make backslashes from auxiliary commands."
|
|
||||||
(py2texi-search-safe "@backslash{}"
|
|
||||||
(replace-match "\\\\")))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-fonts ()
|
|
||||||
"Remove garbage after unstructured font commands."
|
|
||||||
(let (string)
|
|
||||||
(py2texi-search-safe "@destroy"
|
|
||||||
(replace-match "")
|
|
||||||
(when (eq (preceding-char) ?{)
|
|
||||||
(forward-char -1)
|
|
||||||
(setq string (py2texi-tex-arguments 1))
|
|
||||||
(insert (substring string 1 (1- (length string))))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-braces ()
|
|
||||||
"Escape braces for Texinfo."
|
|
||||||
(let (string)
|
|
||||||
(py2texi-search "{"
|
|
||||||
(unless (or (py2texi-protected)
|
|
||||||
(save-excursion
|
|
||||||
(re-search-backward
|
|
||||||
"@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t)))
|
|
||||||
(forward-char -1)
|
|
||||||
(setq string (py2texi-tex-arguments 1))
|
|
||||||
(insert "@" (substring string 0 (1- (length string))) "@}")))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-fix-newlines ()
|
|
||||||
"Remove extra newlines."
|
|
||||||
(py2texi-search "\n\n\n+"
|
|
||||||
(replace-match "\n\n"))
|
|
||||||
(py2texi-search-safe "@item.*\n\n"
|
|
||||||
(delete-backward-char 1))
|
|
||||||
(py2texi-search "@end example"
|
|
||||||
(unless (looking-at "\n\n")
|
|
||||||
(insert "\n"))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-destroy-empties ()
|
|
||||||
"Remove all comments.
|
|
||||||
This avoids some makeinfo errors."
|
|
||||||
(py2texi-search "@c\\>"
|
|
||||||
(unless (eq (py2texi-protected) t)
|
|
||||||
(delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
|
|
||||||
(cond
|
|
||||||
((looking-at "\n\n")
|
|
||||||
(delete-char 1))
|
|
||||||
((save-excursion (re-search-backward "^[ \t]*\\=" nil t))
|
|
||||||
(delete-region (save-excursion (beginning-of-line) (point))
|
|
||||||
(1+ (point))))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-adjust-level ()
|
|
||||||
"Increase heading level to @chapter, if needed.
|
|
||||||
This is only needed for distutils, so it has a very simple form only."
|
|
||||||
(goto-char (point-min))
|
|
||||||
(unless (re-search-forward "@chapter\\>" nil t)
|
|
||||||
(py2texi-search-safe "@section\\>"
|
|
||||||
(replace-match "@chapter" t))
|
|
||||||
(py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
|
|
||||||
(replace-match "" nil nil nil 1))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-texinfo-escape (beg end)
|
|
||||||
"Escape Texinfo special characters in region."
|
|
||||||
(save-excursion
|
|
||||||
(goto-char beg)
|
|
||||||
(while (re-search-forward "[@{}]" end t)
|
|
||||||
(replace-match "@\\&"))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun py2texi-protected ()
|
|
||||||
"Return protection status of the point before current point."
|
|
||||||
(get-text-property (1- (point)) 'py2texi-protected))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Announce
|
|
||||||
|
|
||||||
(provide 'py2texi)
|
|
||||||
|
|
||||||
|
|
||||||
;;; py2texi.el ends here
|
|
@ -1,98 +0,0 @@
|
|||||||
"""Support functions for loading the reference count data file."""
|
|
||||||
__version__ = '$Revision$'
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the expected location of the reference count file:
|
|
||||||
try:
|
|
||||||
p = os.path.dirname(__file__)
|
|
||||||
except NameError:
|
|
||||||
p = os.path.dirname(sys.argv[0])
|
|
||||||
p = os.path.normpath(os.path.join(os.getcwd(), p, os.pardir,
|
|
||||||
"api", "refcounts.dat"))
|
|
||||||
DEFAULT_PATH = p
|
|
||||||
del p
|
|
||||||
|
|
||||||
|
|
||||||
def load(path=DEFAULT_PATH):
|
|
||||||
return loadfile(open(path))
|
|
||||||
|
|
||||||
|
|
||||||
def loadfile(fp):
|
|
||||||
d = {}
|
|
||||||
while 1:
|
|
||||||
line = fp.readline()
|
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
line = line.strip()
|
|
||||||
if line[:1] in ("", "#"):
|
|
||||||
# blank lines and comments
|
|
||||||
continue
|
|
||||||
parts = line.split(":", 4)
|
|
||||||
if len(parts) != 5:
|
|
||||||
raise ValueError("Not enough fields in " + `line`)
|
|
||||||
function, type, arg, refcount, comment = parts
|
|
||||||
if refcount == "null":
|
|
||||||
refcount = None
|
|
||||||
elif refcount:
|
|
||||||
refcount = int(refcount)
|
|
||||||
else:
|
|
||||||
refcount = None
|
|
||||||
#
|
|
||||||
# Get the entry, creating it if needed:
|
|
||||||
#
|
|
||||||
try:
|
|
||||||
entry = d[function]
|
|
||||||
except KeyError:
|
|
||||||
entry = d[function] = Entry(function)
|
|
||||||
#
|
|
||||||
# Update the entry with the new parameter or the result information.
|
|
||||||
#
|
|
||||||
if arg:
|
|
||||||
entry.args.append((arg, type, refcount))
|
|
||||||
else:
|
|
||||||
entry.result_type = type
|
|
||||||
entry.result_refs = refcount
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
class Entry:
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
self.args = []
|
|
||||||
self.result_type = ''
|
|
||||||
self.result_refs = None
|
|
||||||
|
|
||||||
|
|
||||||
def dump(d):
|
|
||||||
"""Dump the data in the 'canonical' format, with functions in
|
|
||||||
sorted order."""
|
|
||||||
items = d.items()
|
|
||||||
items.sort()
|
|
||||||
first = 1
|
|
||||||
for k, entry in items:
|
|
||||||
if first:
|
|
||||||
first = 0
|
|
||||||
else:
|
|
||||||
print
|
|
||||||
s = entry.name + ":%s:%s:%s:"
|
|
||||||
if entry.result_refs is None:
|
|
||||||
r = ""
|
|
||||||
else:
|
|
||||||
r = entry.result_refs
|
|
||||||
print s % (entry.result_type, "", r)
|
|
||||||
for t, n, r in entry.args:
|
|
||||||
if r is None:
|
|
||||||
r = ""
|
|
||||||
print s % (t, n, r)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
d = load()
|
|
||||||
dump(d)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,54 +0,0 @@
|
|||||||
"""Simple script to replace @DATE@ and friends with real information.
|
|
||||||
|
|
||||||
Usage: rewrite.py boilerplate.tex [VAR=value] ... <template >output
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def get_info(fp):
|
|
||||||
s = fp.read()
|
|
||||||
|
|
||||||
d = {}
|
|
||||||
start = s.find(r"\date{")
|
|
||||||
if start >= 0:
|
|
||||||
end = s.find("}", start)
|
|
||||||
date = s[start+6:end]
|
|
||||||
if date == r"\today":
|
|
||||||
date = time.strftime("%B %d, %Y", time.localtime(time.time()))
|
|
||||||
d["DATE"] = date
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
s = sys.stdin.read()
|
|
||||||
if "@" in s:
|
|
||||||
# yes, we actully need to load the replacement values
|
|
||||||
d = get_info(open(sys.argv[1]))
|
|
||||||
for arg in sys.argv[2:]:
|
|
||||||
name, value = arg.split("=", 1)
|
|
||||||
d[name] = value
|
|
||||||
start = 0
|
|
||||||
while 1:
|
|
||||||
start = s.find("@", start)
|
|
||||||
if start < 0:
|
|
||||||
break
|
|
||||||
end = s.find("@", start+1)
|
|
||||||
name = s[start+1:end]
|
|
||||||
if name:
|
|
||||||
value = d.get(name)
|
|
||||||
if value is None:
|
|
||||||
start = end + 1
|
|
||||||
else:
|
|
||||||
s = s[:start] + value + s[end+1:]
|
|
||||||
start = start + len(value)
|
|
||||||
else:
|
|
||||||
# "@@" --> "@"
|
|
||||||
s = s[:start] + s[end:]
|
|
||||||
start = end
|
|
||||||
sys.stdout.write(s)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,67 +0,0 @@
|
|||||||
# Simple makefile to control XML generation for the entire document tree.
|
|
||||||
# This should be used from the top-level directory (Doc/), not the directory
|
|
||||||
# that actually contains this file:
|
|
||||||
#
|
|
||||||
# $ pwd
|
|
||||||
# .../Doc
|
|
||||||
# $ make -f tools/sgmlconv/Makefile
|
|
||||||
|
|
||||||
TOPDIR=.
|
|
||||||
TOOLSDIR=tools
|
|
||||||
|
|
||||||
SGMLRULES=../$(TOOLSDIR)/sgmlconv/make.rules
|
|
||||||
# The 'inst' and 'tut' directories break the conversion, so skip them for now.
|
|
||||||
SUBDIRS=api dist ext lib mac ref
|
|
||||||
SUBMAKE=$(MAKE) -f $(SGMLRULES) TOOLSDIR=../$(TOOLSDIR)
|
|
||||||
|
|
||||||
all: xml
|
|
||||||
|
|
||||||
.PHONY: esis xml
|
|
||||||
.PHONY: $(SUBDIRS)
|
|
||||||
|
|
||||||
xml:
|
|
||||||
for DIR in $(SUBDIRS) ; do \
|
|
||||||
(cd $$DIR && $(SUBMAKE) xml) || exit $$? ; done
|
|
||||||
|
|
||||||
esis:
|
|
||||||
for DIR in $(SUBDIRS) ; do \
|
|
||||||
(cd $$DIR && $(SUBMAKE) esis) || exit $$? ; done
|
|
||||||
|
|
||||||
esis1:
|
|
||||||
for DIR in $(SUBDIRS) ; do \
|
|
||||||
(cd $$DIR && $(SUBMAKE) esis1) || exit $$? ; done
|
|
||||||
|
|
||||||
tarball: xml
|
|
||||||
tar cf - tools/sgmlconv */*.xml | gzip -9 >xml-1.5.2b2.tgz
|
|
||||||
|
|
||||||
api:
|
|
||||||
cd api && $(SUBMAKE)
|
|
||||||
|
|
||||||
dist:
|
|
||||||
cd dist && $(SUBMAKE)
|
|
||||||
|
|
||||||
ext:
|
|
||||||
cd ext && $(SUBMAKE)
|
|
||||||
|
|
||||||
inst:
|
|
||||||
cd inst && $(SUBMAKE)
|
|
||||||
|
|
||||||
lib:
|
|
||||||
cd lib && $(SUBMAKE)
|
|
||||||
|
|
||||||
mac:
|
|
||||||
cd mac && $(SUBMAKE)
|
|
||||||
|
|
||||||
ref:
|
|
||||||
cd ref && $(SUBMAKE)
|
|
||||||
|
|
||||||
tut:
|
|
||||||
cd tut && $(SUBMAKE)
|
|
||||||
|
|
||||||
clean:
|
|
||||||
for DIR in $(SUBDIRS) ; do \
|
|
||||||
(cd $$DIR && $(SUBMAKE) clean) || exit $$? ; done
|
|
||||||
|
|
||||||
clobber:
|
|
||||||
for DIR in $(SUBDIRS) ; do \
|
|
||||||
(cd $$DIR && $(SUBMAKE) clobber) || exit $$? ; done
|
|
@ -1,58 +0,0 @@
|
|||||||
These scripts and Makefile fragment are used to convert the Python
|
|
||||||
documentation in LaTeX format to XML.
|
|
||||||
|
|
||||||
This material is preliminary and incomplete. Python 2.0 is required.
|
|
||||||
|
|
||||||
To convert all documents to XML:
|
|
||||||
|
|
||||||
cd Doc/
|
|
||||||
make -f tools/sgmlconv/Makefile
|
|
||||||
|
|
||||||
To convert one document to XML:
|
|
||||||
|
|
||||||
cd Doc/<document-dir>
|
|
||||||
make -f ../tools/sgmlconv/make.rules TOOLSDIR=../tools
|
|
||||||
|
|
||||||
Please send comments and bug reports to python-docs@python.org.
|
|
||||||
|
|
||||||
|
|
||||||
What do the tools do?
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
latex2esis.py
|
|
||||||
Reads in a conversion specification written in XML
|
|
||||||
(conversion.xml), reads a LaTeX document fragment, and interprets
|
|
||||||
the markup according to the specification. The output is a stream
|
|
||||||
of ESIS events like those created by the nsgmls SGML parser, but
|
|
||||||
is *not* guaranteed to represent a single tree! This is done to
|
|
||||||
allow conversion per entity rather than per document. Since many
|
|
||||||
of the LaTeX files for the Python documentation contain two
|
|
||||||
sections on closely related modules, it is important to allow both
|
|
||||||
of the resulting <section> elements to exist in the same output
|
|
||||||
stream. Additionally, since comments are not supported in ESIS,
|
|
||||||
comments are converted to <COMMENT> elements, which might exist at
|
|
||||||
the same level as the top-level content elements.
|
|
||||||
|
|
||||||
The output of latex2esis.py gets saved as <filename>.esis1.
|
|
||||||
|
|
||||||
docfixer.py
|
|
||||||
This is the really painful part of the conversion. Well, it's the
|
|
||||||
second really painful part, but more of the pain is specific to
|
|
||||||
the structure of the Python documentation and desired output
|
|
||||||
rather than to the parsing of LaTeX markup.
|
|
||||||
|
|
||||||
This script loads the ESIS data created by latex2esis.py into a
|
|
||||||
DOM document *fragment* (remember, the latex2esis.py output may
|
|
||||||
not be well-formed). Once loaded, it walks over the tree many
|
|
||||||
times looking for a variety of possible specific
|
|
||||||
micro-conversions. Most of the code is not in any way "general".
|
|
||||||
After processing the fragment, a new ESIS data stream is written
|
|
||||||
out. Like the input, it may not represent a well-formed
|
|
||||||
document, but does represent a parsed entity.
|
|
||||||
|
|
||||||
The output of docfixer.py is what gets saved in <filename>.esis.
|
|
||||||
|
|
||||||
esis2sgml.py
|
|
||||||
Reads an ESIS stream and convert to SGML or XML. This also
|
|
||||||
converts <COMMENT> elements to real comments. This works quickly
|
|
||||||
because there's not much to actually do.
|
|