"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "README.md" between
pp-2.14.2.tar.gz and pp-2.14.3.tar.gz

About: PP a generic PreProcessor designed for Pandoc (and more generally Markdown and reStructuredText) - macros, literate programming, diagrams, scripts and more.

README.md  (pp-2.14.2):README.md  (pp-2.14.3)
# Warning: PP may not be supported in the future
Their is no plan to support PP from now on. PP is meant to be replaced
by a combination of:
- [UPP](http://cdelord.fr/upp): Lua-scriptable Universal PreProcessor
- [Panda](http://cdelord.fr/panda): Pandoc add-ons (Lua filters for
Pandoc)
Upp and Panda are written in Lua and are way easier to deploy.
# PP - Generic preprocessor (with pandoc in mind) # PP - Generic preprocessor (with pandoc in mind)
[PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is a [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is a
text preprocessor designed for Pandoc (and more generally Markdown and text preprocessor designed for Pandoc (and more generally Markdown and
reStructuredText). reStructuredText).
The [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") The [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)")
package used to contain three preprocessors for package used to contain three preprocessors for
[Pandoc](http://pandoc.org/). [Pandoc](http://pandoc.org/).
skipping to change at line 42 skipping to change at line 31
[DPP](http://cdelord.fr/dpp "DPP - Diagram Preprocessor (for Pandoc)") [DPP](http://cdelord.fr/dpp "DPP - Diagram Preprocessor (for Pandoc)")
are no longer included in are no longer included in
[PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") as [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") as
`pp` can now be used standalone. `dpp` and `gpp` can be found in the `pp` can now be used standalone. `dpp` and `gpp` can be found in the
legacy legacy
[DPP](http://cdelord.fr/dpp "DPP - Diagram Preprocessor (for Pandoc)") [DPP](http://cdelord.fr/dpp "DPP - Diagram Preprocessor (for Pandoc)")
repository. repository.
`pp` now implements: `pp` now implements:
- macros - macros
- literate programming - literate programming
- [GraphViz](http://graphviz.org/), - [GraphViz](http://graphviz.org/),
[PlantUML](http://plantuml.sourceforge.net/), [PlantUML](http://plantuml.sourceforge.net/),
[GraphViz](http://graphviz.org/),
[ditaa](http://ditaa.sourceforge.net/) and [ditaa](http://ditaa.sourceforge.net/) and
[blockdiag](http://blockdiag.com/) diagrams [blockdiag](http://blockdiag.com/) diagrams
- [Asymptote](http://asymptote.sourceforge.net/) and - [Asymptote](http://asymptote.sourceforge.net/) and
[R](https://www.r-project.org/) figures [R](https://www.r-project.org/) figures
- [Bash](https://www.gnu.org/software/bash/), - [Bash](https://www.gnu.org/software/bash/),
[Cmd](https://en.wikipedia.org/wiki/Cmd.exe), [Cmd](https://en.wikipedia.org/wiki/Cmd.exe),
[PowerShell](https://en.wikipedia.org/wiki/PowerShell), [PowerShell](https://en.wikipedia.org/wiki/PowerShell),
[Python](https://www.python.org/), [Lua](http://www.lua.org/), [Python](https://www.python.org/), [Lua](http://www.lua.org/),
[Haskell](https://www.haskell.org/) and [Haskell](https://www.haskell.org/) and
[R](https://www.r-project.org/) scripts [R](https://www.r-project.org/) scripts
- [Mustache](https://github.com/JustusAdam/mustache) - [Mustache](https://github.com/JustusAdam/mustache)
# Warning: PP may not be supported in the future
Their is no plan to support PP from now on. PP is meant to be replaced
by a combination of:
- [UPP](http://cdelord.fr/upp): Lua-scriptable Universal PreProcessor
- [Panda](http://cdelord.fr/panda): Pandoc add-ons (Lua filters for
Pandoc)
Upp and Panda are written in Lua and are way easier to deploy.
# Open source # Open source
[PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is
an Open source software. Anybody can contribute on an Open source software. Anybody can contribute on
[GitHub](https://github.com/CDSoft/pp) to: [GitHub](https://github.com/CDSoft/pp) to:
- suggest or add new features - suggest or add new features
- report or fix bugs - report or fix bugs
- improve the documentation - improve the documentation
- add some nicer examples - add some nicer examples
- find new usages - find new usages
- … - …
# Installation # Installation
**Compilation**: **Compilation**:
1. Download and extract [pp.tgz](http://cdelord.fr/pp/pp.tgz). 1. Download and extract [pp.tgz](http://cdelord.fr/pp/pp.tgz).
2. Run `make`. 2. Run `make`.
[PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is [PP](http://cdelord.fr/pp "PP - Generic Preprocessor (for Pandoc)") is
written in [Haskell](https://www.haskell.org/) and is built with written in [Haskell](https://www.haskell.org/) and is built with
[Stack](https://docs.haskellstack.org/en/stable/README/). On MacOS, [Stack](https://docs.haskellstack.org/en/stable/README/). On MacOS,
running `make` requires the GNU version of `tar` which can be installed running `make` requires the GNU version of `tar` which can be installed
with `brew install gnu-tar`. with `brew install gnu-tar`.
**Docker**: **Docker**:
A Linux docker made by [Joshua Dotson](https://github.com/josdotso) is A Linux docker made by [Joshua Dotson](https://github.com/josdotso) is
available here: available here:
- https://hub.docker.com/r/josdotso/pp - https://hub.docker.com/r/josdotso/pp
- https://github.com/josdotso/docker-pp - https://github.com/josdotso/docker-pp
https://github.com/josdotso/docker-pp
**Installation**: **Installation**:
- Run `make install` to copy `pp` in `~/.local/bin`. - Run `make install` to copy `pp` in `~/.local/bin`.
- or copy `pp` (`pp.exe` on Windows) wherever you want. - or copy `pp` (`pp.exe` on Windows) wherever you want.
or copy `pp` (`pp.exe` on Windows) wherever you want.
`pp` requires (*optionally*) [Graphviz](http://graphviz.org/), `pp` requires (*optionally*) [Graphviz](http://graphviz.org/),
[blockdiag](http://blockdiag.com/), [blockdiag](http://blockdiag.com/),
[Asymptote](http://asymptote.sourceforge.net/), [Asymptote](http://asymptote.sourceforge.net/),
[R](https://www.r-project.org/) and Java [R](https://www.r-project.org/) and Java
([PlantUML](http://plantuml.sourceforge.net/) and ([PlantUML](http://plantuml.sourceforge.net/) and
[ditaa](http://ditaa.sourceforge.net/) are embedded in `pp`). [ditaa](http://ditaa.sourceforge.net/) are embedded in `pp`).
**Precompiled binaries**: **Precompiled binaries**:
The recommended way to get PP binaries is to compile them from the The recommended way to get PP binaries is to compile them from the
sources. Anyway if you have no Haskell compiler, you can try some sources. Anyway if you have no Haskell compiler, you can try some
precompiled binaries. precompiled binaries.
- Latest Linux and Windows binaries: - Latest Linux and Windows binaries:
- Fedora 34 (64 bit): <http://cdelord.fr/pp/pp-linux-x86_64.txz> - Fedora 35 (64 bit): <http://cdelord.fr/pp/pp-linux-x86_64.txz>
- Windows (64 bit): <http://cdelord.fr/pp/pp-win.7z> - Windows (64 bit): <http://cdelord.fr/pp/pp-win.7z>
- Older version archive: - Older version archive:
- Fedora & Windows: <http://cdelord.fr/pp/download.html> - Fedora & Windows: <http://cdelord.fr/pp/download.html>
- User contributed Mac OS binaries (outdated): - User contributed Mac OS binaries (outdated):
- Mac OS (64 bit binaries): - Mac OS (64 bit binaries):
<https://github.com/dlardi/pp/releases/download/v1.0/pp-darwin-x86_64.tx z> <https://github.com/dlardi/pp/releases/download/v1.0/pp-darwin-x86_64.tx z>
# Usage # Usage
`pp` is a simple preprocessor written in Haskell. It’s mainly designed `pp` is a simple preprocessor written in Haskell. It’s mainly designed
for Pandoc but may be used as a generic preprocessor. It is not intended for Pandoc but may be used as a generic preprocessor. It is not intended
to be as powerful as GPP, for instance, but is a simple implementation to be as powerful as GPP, for instance, but is a simple implementation
for my own needs, as well as an opportunity to play with Haskell. for my own needs, as well as an opportunity to play with Haskell.
`pp` takes strings as input and incrementally builds an environment `pp` takes strings as input and incrementally builds an environment
skipping to change at line 147 skipping to change at line 147
`pp` emits the preprocessed document on the standard output. Inputs are `pp` emits the preprocessed document on the standard output. Inputs are
listed on the command line and concatenated, the standard input is used listed on the command line and concatenated, the standard input is used
when no input is specified. when no input is specified.
## Command line ## Command line
`pp` executes arguments in the same order as the command line. It starts `pp` executes arguments in the same order as the command line. It starts
with an initial environment containing: with an initial environment containing:
- the environment variables of the current process - the environment variables of the current process
- a `lang` variable containing the current langage (currently only - a `lang` variable containing the current langage (currently only
French (`fr`), Italian (`it`), Spanish (`es`) and English (`en`) are French (`fr`), Italian (`it`), Spanish (`es`) and English (`en`) are
a `lang` variable containing the current langage (currently only
supported) supported)
- a `format` variable containing the current output format (`html`, - a `format` variable containing the current output format (`html`,
`pdf`, `odt`, `epub` or `mobi`) `pdf`, `odt`, `epub` or `mobi`)
- a `dialect` variable containing the current dialect (`md` or `rst`) - a `dialect` variable containing the current dialect (`md` or `rst`)
The *dialect* is used to format links and images in the output The *dialect* is used to format links and images in the output
documents. Currently only Markdown and reStructuredText are supported. documents. Currently only Markdown and reStructuredText are supported.
If no input file is specified, `pp` preprocesses the standard input. If no input file is specified, `pp` preprocesses the standard input.
The command line arguments are intentionally very basic. The user can The command line arguments are intentionally very basic. The user can
define and undefine variables and list input files. define and undefine variables and list input files.
- **`-v`** **`-v`**
displays the current version and exits. displays the current version and exits.
- **`-h`**
displays some help and exits. **`-h`**
- **`-help`** displays some help and exits.
displays a longer help and exits.
- **`-userhelp`** **`-help`**
displays a longer help for user macros only and exits. displays a longer help and exits.
- **`-DSYMBOL[=VALUE]`** or **`-D SYMBOL[=VALUE]`**
adds the symbol `SYMBOL` to the current environment and associates **`-userhelp`**
it to the optional value `VALUE`. If no value is provided, the displays a longer help for user macros only and exits.
symbol is simply defined with an empty value.
- **`-USYMBOL`** or **`-U SYMBOL`** **`-DSYMBOL[=VALUE]`** or **`-D SYMBOL[=VALUE]`**
removes the symbol `SYMBOL` from the current environment. adds the symbol `SYMBOL` to the current environment and associates it to
- **`-img=PREFIX`** or **`-img PREFIX`** the optional value `VALUE`. If no value is provided, the symbol is
changes the prefix of the images output path. simply defined with an empty value.
- **`-import=FILE`** or **`-import FILE`**
preprocessed `FILE` but discards its output. It only keeps macro **`-USYMBOL`** or **`-U SYMBOL`**
definitions and other side effects. removes the symbol `SYMBOL` from the current environment.
- **`-M TARGET`** or **`-M=TARGET`**
tracks dependencies and outputs a make rule listing the **`-img=PREFIX`** or **`-img PREFIX`**
dependencies. The target name is necessary since it can not be changes the prefix of the images output path.
infered by `pp`. This option only lists files that are imported,
included and used with `mdate` and `csv`macros. **`-import=FILE`** or **`-import FILE`**
- **`-plantuml=FILE`** or **`-plantuml FILE`** preprocessed `FILE` but discards its output. It only keeps macro
use `FILE` instead of the embedded plantuml.jar file. definitions and other side effects.
- **`-ditaa=FILE`** or **`-ditaa FILE`**
use `FILE` instead of the embedded ditaa.jar file. **`-M TARGET`** or **`-M=TARGET`**
- **`-<macro>[=<arg>]`** tracks dependencies and outputs a make rule listing the dependencies.
calls a builtin macro with an optional argument (see `pp -help` for The target name is necessary since it can not be infered by `pp`. This
the full macro list). Some macros may prevent pp from reading stdin option only lists files that are imported, included and used with
when no file is given on the command line (`langs`, `formats`, `mdate` and `csv`macros.
`dialects`, `os`, `arch`, `macros`, `usermacros`).
**`-plantuml=FILE`** or **`-plantuml FILE`**
use `FILE` instead of the embedded plantuml.jar file.
**`-ditaa=FILE`** or **`-ditaa FILE`**
use `FILE` instead of the embedded ditaa.jar file.
**`-<macro>[=<arg>]`**
calls a builtin macro with an optional argument (see `pp -help` for the
full macro list). Some macros may prevent pp from reading stdin when no
file is given on the command line (`langs`, `formats`, `dialects`, `os`,
`arch`, `macros`, `usermacros`).
Other arguments are filenames. Other arguments are filenames.
Files are read and preprocessed using the current state of the Files are read and preprocessed using the current state of the
environment. The special filename “`-`” can be used to preprocess the environment. The special filename “`-`” can be used to preprocess the
standard input. standard input.
## Macros ## Macros
Built-in macros are hard coded in `pp` and can not be redefined. User Built-in macros are hard coded in `pp` and can not be redefined. User
defined macros are simple text substitutions that may have any number of defined macros are simple text substitutions that may have any number of
parameters (named `!1` to `!n`). User macros can be (re)defined on the parameters (named `!1` to `!n`). User macros can be (re)defined on the
command line or in the documents. command line or in the documents.
Macro names are: Macro names are:
- case sensitive (i.e.: `!my_macro` and `!My_Macro` are different - case sensitive (i.e.: `!my_macro` and `!My_Macro` are different
macros) macros)
- made of letters, digits and underscores (`a-zA-Z0-9_`) - made of letters, digits and underscores (`a-zA-Z0-9_`)
User macros starting with `_` are not listed in macros lists and help User macros starting with `_` are not listed in macros lists and help
texts. texts.
To get the value of a variable you just have to write its name after a To get the value of a variable you just have to write its name after a
‘`!`’. Macros can be given arguments. Each argument is enclosed in ‘`!`’. Macros can be given arguments. Each argument is enclosed in
parenthesis, curly braces or square brackets. For instance, the macro parenthesis, curly braces or square brackets. For instance, the macro
`foo` with two arguments can be called as `!foo(x)(y)`, `!foo{x}{y}` or `foo` with two arguments can be called as `!foo(x)(y)`, `!foo{x}{y}` or
even `!foo[x][y]`. Mixing brackets, braces and parenthesis within a even `!foo[x][y]`. Mixing brackets, braces and parenthesis within a
single macro is not allowed: all parameters must be enclosed within the single macro is not allowed: all parameters must be enclosed within the
skipping to change at line 255 skipping to change at line 266
You can choose the syntax that works better with your favorite editor You can choose the syntax that works better with your favorite editor
and syntax colorization. and syntax colorization.
For most of the macros, arguments are preprocessed before executing the For most of the macros, arguments are preprocessed before executing the
macro. Macros results are not preprocessed (unless used as a parameter macro. Macros results are not preprocessed (unless used as a parameter
of an outer macro). The `include` macro is an exception: its output is of an outer macro). The `include` macro is an exception: its output is
also preprocessed. The `rawinclude` macro can include a file without also preprocessed. The `rawinclude` macro can include a file without
preprocessing it. preprocessing it.
- **`define`**, **`def`** **`define`**, **`def`**
`!def[ine](SYMBOL)[[(DOC)](VALUE)]` adds the symbol `SYMBOL` to the `!def[ine](SYMBOL)[[(DOC)](VALUE)]` adds the symbol `SYMBOL` to the
current environment and associate it with the optional value current environment and associate it with the optional value `VALUE`.
`VALUE`. Arguments are denoted by `!1` … `!n` in `VALUE`. If `DOC` Arguments are denoted by `!1` … `!n` in `VALUE`. If `DOC` is given it is
is given it is used to document the macro (see the `-help` option). used to document the macro (see the `-help` option).
- **`undefine`**, **`undef`**
`!undef[ine](SYMBOL)` removes the symbol `SYMBOL` from the current **`undefine`**, **`undef`**
environment. `!undef[ine](SYMBOL)` removes the symbol `SYMBOL` from the current
- **`defined`** environment.
`!defined(SYMBOL)` returns 1 if `SYMBOL` is defined, 0 otherwise.
- **`rawdef`** **`defined`**
`!rawdef(X)` returns the raw (unevaluated) definition of `X`. `!defined(SYMBOL)` returns 1 if `SYMBOL` is defined, 0 otherwise.
- **`ifdef`**
`!ifdef(SYMBOL)(TEXT_IF_DEFINED)[(TEXT_IF_NOT_DEFINED)]` returns **`rawdef`**
`TEXT_IF_DEFINED` if `SYMBOL` is defined or `TEXT_IF_NOT_DEFINED` if `!rawdef(X)` returns the raw (unevaluated) definition of `X`.
it is not defined.
- **`ifndef`** **`ifdef`**
`!ifndef(SYMBOL)(TEXT_IF_NOT_DEFINED)[(TEXT_IF_DEFINED)]` returns `!ifdef(SYMBOL)(TEXT_IF_DEFINED)[(TEXT_IF_NOT_DEFINED)]` returns
`TEXT_IF_NOT_DEFINED` if `SYMBOL` is not defined or `TEXT_IF_DEFINED` if `SYMBOL` is defined or `TEXT_IF_NOT_DEFINED` if it
`TEXT_IF_DEFINED` if it is defined. is not defined.
- **`ifeq`**
`!ifeq(X)(Y)(TEXT_IF_EQUAL)[(TEXT_IF_DIFFERENT)]` returns **`ifndef`**
`TEXT_IF_EQUAL` if `X` and `Y` are equal or `TEXT_IF_DIFFERENT` if `!ifndef(SYMBOL)(TEXT_IF_NOT_DEFINED)[(TEXT_IF_DEFINED)]` returns
`X` and `Y` are different. Two pieces of text are equal if all `TEXT_IF_NOT_DEFINED` if `SYMBOL` is not defined or `TEXT_IF_DEFINED` if
non-space characters are the same. it is defined.
- **`ifne`**
`!ifne(X)(Y)(TEXT_IF_DIFFERENT)[(TEXT_IF_EQUAL)]` returns **`ifeq`**
`TEXT_IF_DIFFERENT` if `X` and `Y` are different or `TEXT_IF_EQUAL` `!ifeq(X)(Y)(TEXT_IF_EQUAL)[(TEXT_IF_DIFFERENT)]` returns
if `X` and `Y` are equal. `TEXT_IF_EQUAL` if `X` and `Y` are equal or `TEXT_IF_DIFFERENT` if `X`
- **`if`** and `Y` are different. Two pieces of text are equal if all non-space
`!if(EXPR)(TEXT_IF_EXPR_IS_TRUE)[(TEXT_IF_EXPR_IS_FALSE)]` returns characters are the same.
`TEXT_IF_EXPR_IS_TRUE` if `EXPR` is true or `TEXT_IF_EXPR_IS_FALSE`
if `EXPR` is false. **`ifne`**
- **`eval`** `!ifne(X)(Y)(TEXT_IF_DIFFERENT)[(TEXT_IF_EQUAL)]` returns
`!eval(EXPR) evaluates`EXPR\`. `TEXT_IF_DIFFERENT` if `X` and `Y` are different or `TEXT_IF_EQUAL` if
- **`info`** `X` and `Y` are equal.
`!info(MESSAGE) prints`MESSAGE\` on stderr.
- **`warning`**, **`warn`** **`if`**
`!warn[ing](MESSAGE) prints`MESSAGE\` on stderr. `!if(EXPR)(TEXT_IF_EXPR_IS_TRUE)[(TEXT_IF_EXPR_IS_FALSE)]` returns
- **`error`** `TEXT_IF_EXPR_IS_TRUE` if `EXPR` is true or `TEXT_IF_EXPR_IS_FALSE` if
`!error[(CODE)](MESSAGE) prints`MESSAGE`on stderr and exits with `EXPR` is false.
error code`CODE\`.
- **`exit`** **`eval`**
`!exit(CODE) exits with error code`CODE\`. `!eval(EXPR) evaluates`EXPR\`.
- **`import`**
`!import(FILENAME)` works as `!include(FILENAME)` but returns **`info`**
nothing. This is useful to import macro definitions. `!info(MESSAGE) prints`MESSAGE\` on stderr.
- **`include`**, **`inc`**
`!inc[lude](FILENAME)` preprocesses and returns the content of the **`warning`**, **`warn`**
file named `FILENAME` and includes it in the current document. If `!warn[ing](MESSAGE) prints`MESSAGE\` on stderr.
the file path is relative it is searched first in the directory of
the current file then in the directory of the main file. **`error`**
- **`raw`** `!error[(CODE)](MESSAGE) prints`MESSAGE`on stderr and exits with error code`CODE
`!raw(TEXT)` returns `TEXT` without any preprocessing. \`.
- **`rawinclude`**, **`rawinc`**
`!rawinc[lude](FILE)` returns the content of `FILE` without any **`exit`**
preprocessing. `!exit(CODE) exits with error code`CODE\`.
- **`comment`**
`!comment(TEXT)` considers `TEXT` as well as any additional **`import`**
parameters as comment. Nothing is preprocessed or returned. `!import(FILENAME)` works as `!include(FILENAME)` but returns nothing.
- **`quiet`** This is useful to import macro definitions.
`!quiet(TEXT)` quietly preprocesses `TEXT` and returns nothing. Only
the side effects (e.g. macro definitions) are kept in the **`include`**, **`inc`**
environment. `!inc[lude](FILENAME)` preprocesses and returns the content of the file
- **`pp`** named `FILENAME` and includes it in the current document. If the file
`!pp(TEXT)` preprocesses and return `TEXT`. This macro is useful to path is relative it is searched first in the directory of the current
preprocess the output of script macros for instance (`!sh`, file then in the directory of the main file.
`!python`, …).
- **`mustache`** **`raw`**
`!mustache(JSON/YAML file)(TEMPLATE)` preprocesses `TEMPLATE` with `!raw(TEXT)` returns `TEXT` without any preprocessing.
mustache, using a `JSON/YAML file`.
- **`mdate`** **`rawinclude`**, **`rawinc`**
`!mdate(FILES)` returns the modification date of the most recent `!rawinc[lude](FILE)` returns the content of `FILE` without any
file. preprocessing.
- **`main`**
`!main` returns the name of the main file (given on the command **`comment`**
line). `!comment(TEXT)` considers `TEXT` as well as any additional parameters
- **`file`** as comment. Nothing is preprocessed or returned.
`!file` returns the name of the current file.
- **`root`** **`quiet`**
`!root` returns the directory name of the main file. `!quiet(TEXT)` quietly preprocesses `TEXT` and returns nothing. Only the
- **`cwd`** side effects (e.g. macro definitions) are kept in the environment.
`!cwd` returns the directory name of the current file.
- **`lang`** **`pp`**
`!lang` returns the current language. `!pp(TEXT)` preprocesses and return `TEXT`. This macro is useful to
- **`langs`** preprocess the output of script macros for instance (`!sh`, `!python`,
`!langs` lists the known languages (en, fr, it, es). …).
- **`en`**
`!en(TEXT)` returns `TEXT` if the current language is `en`. **`mustache`**
- **`fr`** `!mustache(JSON/YAML file)(TEMPLATE)` preprocesses `TEMPLATE` with
`!fr(TEXT)` returns `TEXT` if the current language is `fr`. mustache, using a `JSON/YAML file`.
- **`it`**
`!it(TEXT)` returns `TEXT` if the current language is `it`. **`mdate`**
- **`es`** `!mdate(FILES)` returns the modification date of the most recent file.
`!es(TEXT)` returns `TEXT` if the current language is `es`.
- **`format`** **`main`**
`!format` returns the current output format. `!main` returns the name of the main file (given on the command line).
- **`formats`**
`!formats` lists the known formats (html, pdf, odf, epub, mobi). **`file`**
- **`html`** `!file` returns the name of the current file.
`!html(TEXT)` returns `TEXT` if the current format is `html`.
- **`pdf`** **`root`**
`!pdf(TEXT)` returns `TEXT` if the current format is `pdf`. `!root` returns the directory name of the main file.
- **`odf`**
`!odf(TEXT)` returns `TEXT` if the current format is `odf`. **`cwd`**
- **`epub`** `!cwd` returns the directory name of the current file.
`!epub(TEXT)` returns `TEXT` if the current format is `epub`.
- **`mobi`** **`lang`**
`!mobi(TEXT)` returns `TEXT` if the current format is `mobi`. `!lang` returns the current language.
- **`dialect`**
`!dialect` returns the current output dialect. **`langs`**
- **`dialects`** `!langs` lists the known languages (en, fr, it, es).
`!dialects` lists the kown output dialects (md, rst).
- **`md`** **`en`**
`!md(TEXT)` returns `TEXT` if the current dialect is `md`. `!en(TEXT)` returns `TEXT` if the current language is `en`.
- **`rst`**
`!rst(TEXT)` returns `TEXT` if the current dialect is `rst`. **`fr`**
- **`env`** `!fr(TEXT)` returns `TEXT` if the current language is `fr`.
`!env(VARNAME)` preprocesses and returns the value of the process
environment variable `VARNAME`. **`it`**
- **`os`** `!it(TEXT)` returns `TEXT` if the current language is `it`.
`!os` returns the OS name (e.g. `linux` on Linux, `darwin` on MacOS,
`windows` on Windows). **`es`**
- **`arch`** `!es(TEXT)` returns `TEXT` if the current language is `es`.
`!arch` returns the machine architecture (e.g. `x86_64`, `i386`, …).
- **`add`** **`format`**
`!add(VARNAME)[(INCREMENT)]` computes `VARNAME+INCREMENT` and stores `!format` returns the current output format.
the result to `VARNAME`. The default value of the increment is 1.
- **`append`** **`formats`**
`!append(VARNAME)[(TEXT)]` appends `TEXT` to `!VARNAME` and stores `!formats` lists the known formats (html, pdf, odf, epub, mobi).
the result to `VARNAME`.
- **`exec`** **`html`**
`!exec(COMMAND)` executes a shell command with the default shell `!html(TEXT)` returns `TEXT` if the current format is `html`.
(`sh` or `cmd` according to the OS).
- **`rawexec`** **`pdf`**
`!rawexec` is *deprecated*. See exec. `!pdf(TEXT)` returns `TEXT` if the current format is `pdf`.
- **`sh`**
`!sh(CMD)` executes `CMD` in a `sh` shell. **`odf`**
- **`bash`** `!odf(TEXT)` returns `TEXT` if the current format is `odf`.
`!bash(CMD)` executes `CMD` in a `bash` shell.
- **`zsh`** **`epub`**
`!zsh(CMD)` executes `CMD` in a `zsh` shell. `!epub(TEXT)` returns `TEXT` if the current format is `epub`.
- **`fish`**
`!fish(CMD)` executes `CMD` in a `fish` shell. **`mobi`**
- **`cmd`** `!mobi(TEXT)` returns `TEXT` if the current format is `mobi`.
`!cmd(CMD)` executes `CMD` in a Windows shell (cmd.exe).
- **`bat`** **`dialect`**
`!bat` is *deprecated*. See cmd. `!dialect` returns the current output dialect.
- **`python`**
`!python(CMD)` executes `CMD` with the default Python interpretor. **`dialects`**
- **`python2`** `!dialects` lists the kown output dialects (md, rst).
`!python2(CMD)` executes `CMD` with Python 2.
- **`python3`** **`md`**
`!python3(CMD)` executes `CMD` with Python 3. `!md(TEXT)` returns `TEXT` if the current dialect is `md`.
- **`lua`**
`!lua(CMD)` executes `CMD` with Lua. **`rst`**
- **`haskell`** `!rst(TEXT)` returns `TEXT` if the current dialect is `rst`.
`!haskell(CMD)` executes `CMD` as a Haskell script with
`runhaskell`. **`env`**
- **`stack`** `!env(VARNAME)` preprocesses and returns the value of the process
`!stack(CMD)` executes `CMD` as a Haskell script with `stack`. environment variable `VARNAME`.
- **`Rscript`**
`!Rscript(CMD)` executes `CMD` as a R script with Rscript. **`os`**
- **`powershell`** `!os` returns the OS name (e.g. `linux` on Linux, `darwin` on MacOS,
`!cmd(CMD)` executes `CMD` in a Windows shell (Powershell). `windows` on Windows).
- **`dot`**
`!dot(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a dot image with **`arch`**
Graphviz. `!arch` returns the machine architecture (e.g. `x86_64`, `i386`, …).
- **`neato`**
`!neato(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a neato image **`add`**
with Graphviz. `!add(VARNAME)[(INCREMENT)]` computes `VARNAME+INCREMENT` and stores the
- **`twopi`** result to `VARNAME`. The default value of the increment is 1.
`!twopi(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a twopi image
with Graphviz. **`append`**
- **`circo`** `!append(VARNAME)[(TEXT)]` appends `TEXT` to `!VARNAME` and stores the
`!circo(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a circo image result to `VARNAME`.
with Graphviz.
- **`fdp`** **`exec`**
`!fdp(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a fdp image with `!exec(COMMAND)` executes a shell command with the default shell (`sh`
Graphviz. or `cmd` according to the OS).
- **`sfdp`**
`!sfdp(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a sfdp image **`rawexec`**
with Graphviz. `!rawexec` is *deprecated*. See exec.
- **`patchwork`**
`!patchwork(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a patchwork **`sh`**
image with Graphviz. `!sh(CMD)` executes `CMD` in a `sh` shell.
- **`osage`**
`!osage(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a osage image **`bash`**
with Graphviz. `!bash(CMD)` executes `CMD` in a `bash` shell.
- **`uml`**
`!uml(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a uml image with **`zsh`**
PlantUML. `!zsh(CMD)` executes `CMD` in a `zsh` shell.
- **`ditaa`**
`!ditaa(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a ditaa image **`fish`**
with Ditaa. `!fish(CMD)` executes `CMD` in a `fish` shell.
- **`blockdiag`**
`!blockdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a blockdiag **`cmd`**
image with BlockDiag. `!cmd(CMD)` executes `CMD` in a Windows shell (cmd.exe).
- **`seqdiag`**
`!seqdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a seqdiag **`bat`**
image with BlockDiag. `!bat` is *deprecated*. See cmd.
- **`actdiag`**
`!actdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a actdiag **`python`**
image with BlockDiag. `!python(CMD)` executes `CMD` with the default Python interpretor.
- **`nwdiag`**
`!nwdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a nwdiag image **`python2`**
with BlockDiag. `!python2(CMD)` executes `CMD` with Python 2.
- **`rackdiag`**
`!rackdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a rackdiag **`python3`**
image with BlockDiag. `!python3(CMD)` executes `CMD` with Python 3.
- **`packetdiag`**
`!packetdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a **`lua`**
packetdiag image with BlockDiag. `!lua(CMD)` executes `CMD` with Lua.
- **`asy`**
`!asy(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a asy image with **`haskell`**
Asymptote. `!haskell(CMD)` executes `CMD` as a Haskell script with `runhaskell`.
- **`Rplot`**
`!Rplot(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a Rplot image **`stack`**
with R. `!stack(CMD)` executes `CMD` as a Haskell script with `stack`.
- **`literate`**, **`lit`**
`!lit[erate](FILENAME)[(LANG)][(CONTENT)]` appends `CONTENT` to the **`Rscript`**
file `FILENAME`. If `FILENAME` starts with `@` it’s a macro, not a `!Rscript(CMD)` executes `CMD` as a R script with Rscript.
file. The output is highlighted using the programming language
`LANGUAGE`. The list of possible languages is given by `pandoc **`powershell`**
--list-highlight-languages`. Files are actually written when all the `!cmd(CMD)` executes `CMD` in a Windows shell (Powershell).
documents have been successfully preprocessed. Macros are expanded
when the files are written. This macro provides basic literate **`dot`**
programming features. If `LANG` is not given, pp uses the previously `!dot(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a dot image with
defined language for the same file or macro or a default language Graphviz.
according to its name. If `CONTENT`is not given, pp returns the
current content of `FILENAME`. **`neato`**
- **`flushliterate`**, **`flushlit`** `!neato(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a neato image with
`!flushlit[erate]` writes files built with `!lit` before reaching Graphviz.
the end of the document. This macro is automatically executed before
any script execution or file inclusion with `!src`. **`twopi`**
- **`source`**, **`src`** `!twopi(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a twopi image with
`!source(FILENAME)[(LANG)]` or `!src(FILENAME)[(LANG)]` formats an Graphviz.
existing source file in a colorized code block.
- **`codeblock`** **`circo`**
`!codeblock(LENGTH)[(CHAR)]` sets the default line separator for `!circo(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a circo image with
code blocks. The default value is a 70 tilda row Graphviz.
(`!codeclock(70)(~)`).
- **`indent`** **`fdp`**
`!indent[(N)](BLOCK)` indents each line of a block with `N` spaces. `!fdp(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a fdp image with
The default value of `N` is 4 spaces. Graphviz.
- **`csv`**
`!csv(FILENAME)[(HEADER)]` converts a CSV file to a Markdown or **`sfdp`**
reStructuredText table. `HEADER` defines the header of the table, `!sfdp(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a sfdp image with
fields are separated by pipes (`|`). If `HEADER` is not defined, the Graphviz.
first line of the file is used as the header of the table.
- **`macrochars`** **`patchwork`**
`!macrochars(CHARS)` defines the chars used to call a macro. The `!patchwork(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a patchwork
default value is `"!"`. Any non space character can start a macro image with Graphviz.
call (e.g. after `!macrochars(!\)` both `!foo` and `\foo` are valid
macro calls. **`osage`**
- **`macroargs`** `!osage(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a osage image with
`!macroargs(CHARS)` defines the chars used to separate macro Graphviz.
arguments. The default value is `"(){}[]"` (e.g. after
`!macroargs(()«»)` both `!foo(...)` and `!foo«...»` are valid macro **`uml`**
calls). `!uml(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a uml image with
- **`macroblockargs`** PlantUML.
`!macroblockargs(CHARS)` defines the chars used to separate macro
block arguments. The default value is ``"~`"``. **`ditaa`**
- **`literatemacrochars`** `!ditaa(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a ditaa image with
`!literatemacrochars(CHARS)` defines the chars used to identify Ditaa.
literate programming macros. The default value is `"@"`. Any non
space character can start a literate programming macro (e.g. after **`blockdiag`**
`!literatemacrochars(@&)` both `@foo` and `&foo` are valid macro `!blockdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a blockdiag
calls. image with BlockDiag.
- **`macros`**
`!macros` lists the builtin macros. **`seqdiag`**
- **`usermacros`** `!seqdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a seqdiag image
`!usermacros` lists the user macros. with BlockDiag.
- **`help`**
`!help` prints built-in macro help. **`actdiag`**
- **`userhelp`** `!actdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a actdiag image
`!userhelp` prints user macro help. with BlockDiag.
**`nwdiag`**
`!nwdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a nwdiag image
with BlockDiag.
**`rackdiag`**
`!rackdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a rackdiag image
with BlockDiag.
**`packetdiag`**
`!packetdiag(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a packetdiag
image with BlockDiag.
**`asy`**
`!asy(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a asy image with
Asymptote.
**`Rplot`**
`!Rplot(IMAGE)[(LEGEND)](GRAPH DESCRIPTION)` renders a Rplot image
with R.
**`literate`**, **`lit`**
`!lit[erate](FILENAME)[(LANG)][(CONTENT)]` appends `CONTENT` to the file
`FILENAME`. If `FILENAME` starts with `@` it’s a macro, not a file. The
output is highlighted using the programming language `LANGUAGE`. The
list of possible languages is given by
`pandoc --list-highlight-languages`. Files are actually written when all
the documents have been successfully preprocessed. Macros are expanded
when the files are written. This macro provides basic literate
programming features. If `LANG` is not given, pp uses the previously
defined language for the same file or macro or a default language
according to its name. If `CONTENT`is not given, pp returns the current
content of `FILENAME`.
**`flushliterate`**, **`flushlit`**
`!flushlit[erate]` writes files built with `!lit` before reaching the
end of the document. This macro is automatically executed before any
script execution or file inclusion with `!src`.
**`source`**, **`src`**
`!source(FILENAME)[(LANG)]` or `!src(FILENAME)[(LANG)]` formats an
existing source file in a colorized code block.
**`codeblock`**
`!codeblock(LENGTH)[(CHAR)]` sets the default line separator for code
blocks. The default value is a 70 tilda row (`!codeclock(70)(~)`).
**`indent`**
`!indent[(N)](BLOCK)` indents each line of a block with `N` spaces. The
default value of `N` is 4 spaces.
**`csv`**
`!csv(FILENAME)[(HEADER)]` converts a CSV file to a Markdown or
reStructuredText table. `HEADER` defines the header of the table, fields
are separated by pipes (`|`). If `HEADER` is not defined, the first line
of the file is used as the header of the table.
**`macrochars`**
`!macrochars(CHARS)` defines the chars used to call a macro. The default
value is `"!"`. Any non space character can start a macro call
(e.g. after `!macrochars(!\)` both `!foo` and `\foo` are valid macro
calls.
**`macroargs`**
`!macroargs(CHARS)` defines the chars used to separate macro arguments.
The default value is `"(){}[]"` (e.g. after `!macroargs(()«»)` both
`!foo(...)` and `!foo«...»` are valid macro calls).
**`macroblockargs`**
`!macroblockargs(CHARS)` defines the chars used to separate macro block
arguments. The default value is `` "~`" ``.
**`literatemacrochars`**
`!literatemacrochars(CHARS)` defines the chars used to identify literate
programming macros. The default value is `"@"`. Any non space character
can start a literate programming macro (e.g. after
`!literatemacrochars(@&)` both `@foo` and `&foo` are valid macro calls.
**`macros`**
`!macros` lists the builtin macros.
**`usermacros`**
`!usermacros` lists the user macros.
**`help`**
`!help` prints built-in macro help.
**`userhelp`**
`!userhelp` prints user macro help.
# Expressions # Expressions
The `!if` and `!eval` macros take an expression and evaluate it. The `!if` and `!eval` macros take an expression and evaluate it.
Expressions are made of: Expressions are made of:
- integers - integers
- string (`"..."`) - string (`"..."`)
- integer operators (`+`, `-`, `*`, `/`) - integer operators (`+`, `-`, `*`, `/`)
- boolean operators (`!`, `not`, `&&`, `and`, `||`, `or`, `xor`) - boolean operators (`!`, `not`, `&&`, `and`, `||`, `or`, `xor`)
- relational operators (`==`, `/=`, `!=`, `<`, `<=`, `>`, `>=`) - relational operators (`==`, `/=`, `!=`, `<`, `<=`, `>`, `>=`)
- parentheses, brackets and braces - parentheses, brackets and braces
parentheses, brackets and braces
Boolean values are coded as integers or string (`0` and `""` are false, Boolean values are coded as integers or string (`0` and `""` are false,
other values are true). other values are true).
Macros can be called in expressions. They are preprocessed before Macros can be called in expressions. They are preprocessed before
evaluating the expression. evaluating the expression.
e.g.: e.g.:
!if( !defined(FOO) or !BAR == 42 ) (say something) !if( !defined(FOO) or !BAR == 42 ) (say something)
skipping to change at line 596 skipping to change at line 695
puts("Goodbye."); puts("Goodbye.");
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
# Diagram and script examples # Diagram and script examples
## Diagrams ## Diagrams
Diagrams are written in code blocks as argument of a diagram macro. The Diagrams are written in code blocks as argument of a diagram macro. The
first line contains the macro: first line contains the macro:
- the diagram generator (the macro name) - the diagram generator (the macro name)
- the image name with or without the extension (first argument) - the image name with or without the extension (first argument)
- the default format is `svg` if no extension is provided (unless - the default format is `svg` if no extension is provided (unless
for ditaa diagrams which support `png` only) for ditaa diagrams which support `png` only)
- the supported formats are `png`, `svg` and ‘pdf’ (PDF support is - the supported formats are `png`, `svg` and ‘pdf’ (PDF support is
partial and may not work with PlantUML) partial and may not work with PlantUML)
- the legend (second optional argument) - the legend (second optional argument)
Block delimiters are made of three or more tilda or back quotes, at the Block delimiters are made of three or more tilda or back quotes, at the
beginning of the line (no space and no tab). The end delimiter must at beginning of the line (no space and no tab). The end delimiter must at
least as long as the beginning delimiter. least as long as the beginning delimiter.
!dot(path/imagename)(optional legend) !dot(path/imagename)(optional legend)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
graph { graph {
"source code of the diagram" "source code of the diagram"
} }
skipping to change at line 625 skipping to change at line 724
This extremely meaningful diagram is rendered as `path/imagename.svg` This extremely meaningful diagram is rendered as `path/imagename.svg`
and looks like: and looks like:
![optional legend](doc/img/pp-syntax.svg) ![optional legend](doc/img/pp-syntax.svg)
The image file extension can be `.svg`, `.png` or `pdf`. `SVG` is the The image file extension can be `.svg`, `.png` or `pdf`. `SVG` is the
default format if no extension is provided (unless for ditaa diagrams). default format if no extension is provided (unless for ditaa diagrams).
`!dot(path/imagename.svg)(optional legend)` or `!dot(path/imagename.svg)(optional legend)` or
`!dot(path/imagename)(optional legend)` are rendered as `!dot(path/imagename)(optional legend)` are rendered as
`path/imagename.svg`. `!dot(path/imagename.png)(optional legend)` is `path/imagename.svg`. `!dot(path/imagename.png)(optional legend)` is
rendered as `path/imagename.png`. `!dot(path/imagename.pdf)(optional rendered as `path/imagename.png`.
legend)` is rendered as `path/imagename.pdf` (if supported). `!dot(path/imagename.pdf)(optional legend)` is rendered as
`path/imagename.pdf` (if supported).
The image link in the output markdown document may have to be different The image link in the output markdown document may have to be different
than the actual path in the file system. This happens when then `.md` or than the actual path in the file system. This happens when then `.md` or
`.html` files are not generated in the same path than the source `.html` files are not generated in the same path than the source
document. Brackets can be used to specify the part of the path that document. Brackets can be used to specify the part of the path that
belongs to the generated image but not to the link in the output belongs to the generated image but not to the link in the output
document. For instance a diagram declared as: document. For instance a diagram declared as:
!dot([mybuildpath/]img/diag42)... !dot([mybuildpath/]img/diag42)...
skipping to change at line 651 skipping to change at line 751
and the link in the output document will be: and the link in the output document will be:
img/diag42.png img/diag42.png
For instance, if you use Pandoc to generate HTML documents with diagrams For instance, if you use Pandoc to generate HTML documents with diagrams
in a different directory, there are two possibilities: in a different directory, there are two possibilities:
1. the document is a self contained HTML file (option 1. the document is a self contained HTML file (option
`--self-contained`), i.e. the CSS and images are stored inside the `--self-contained`), i.e. the CSS and images are stored inside the
document: document:
- the CSS path shall be the actual path where the CSS file is - the CSS path shall be the actual path where the CSS file is
stored stored
- the image path in diagrams shall be the actual path where the - the image path in diagrams shall be the actual path where the
images are stored (otherwise Pandoc won’t find them) images are stored (otherwise Pandoc won’t find them)
- e.g.: `outputpath/img/diag42` - e.g.: `outputpath/img/diag42`
2. the document is not self contained, i.e. the CSS and images are 2. the document is not self contained, i.e. the CSS and images are
stored apart from the document: stored apart from the document:
- the CSS path shall be relative to the output document - the CSS path shall be relative to the output document
- the image path in diagrams shall be relative to output document - the image path in diagrams shall be relative to output document
in HTML links and shall also describe the actual path where the in HTML links and shall also describe the actual path where the
images are stored. images are stored.
- e.g.: `[outputpath/]img/diag42` - e.g.: `[outputpath/]img/diag42`
Pandoc also accepts additional attributes on images (`link_attributes` Pandoc also accepts additional attributes on images (`link_attributes`
extension). These attributes can be added between curly brackets to the extension). These attributes can be added between curly brackets to the
first argument. e.g.: first argument. e.g.:
!dot(image.png { width=50 % })(caption)(...) !dot(image.png { width=50 % })(caption)(...)
will generate the following link in the markdown output: will generate the following link in the markdown output:
![caption](image.png){ width=50 % } ![caption](image.png){ width=50 % }
The diagram generator can be: The diagram generator can be:
- dot - dot
- neato - neato
- twopi - twopi
- circo - circo
- fdp - fdp
- sfdp - sfdp
- patchwork - patchwork
- osage - osage
- uml - uml
- ditaa - ditaa
- blockdiag - blockdiag
- seqdiag - seqdiag
- actdiag - actdiag
- nwdiag - nwdiag
- rackdiag - rackdiag
- packetdiag - packetdiag
- asy - asy
- Rplot - Rplot
Rplot
`pp` will not create any directory, the path where the image is written `pp` will not create any directory, the path where the image is written
must already exist. must already exist.
![](doc/img/pp-generators.svg) ![](doc/img/pp-generators.svg)
## Scripts ## Scripts
Scripts are also written in code blocks as arguments of a macro. Scripts are also written in code blocks as arguments of a macro.
skipping to change at line 715 skipping to change at line 815
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
echo Hello World! echo Hello World!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With no surprise, this script generates: With no surprise, this script generates:
Hello World! Hello World!
The script language macro can be: The script language macro can be:
- `sh`, `bash`, `zsh`, `fish` or any other shell with `sh` and a - `sh`, `bash`, `zsh`, `fish` or any other shell with `sh` and a
[shebang header](https://en.wikipedia.org/wiki/Shebang_\(Unix\)) [shebang header](https://en.wikipedia.org/wiki/Shebang_(Unix))
- `python` - `python`
- `lua` - `lua`
- `haskell` (or `stack`) - `haskell` (or `stack`)
- `Rscript` - `Rscript`
- `cmd` (DOS/Windows batch language) - `cmd` (DOS/Windows batch language)
- `powershell` (Windows only) - `powershell` (Windows only)
`powershell` (Windows only)
`pp` will create a temporary script before calling the associated `pp` will create a temporary script before calling the associated
interpretor. interpretor.
![](doc/img/pp-scripts.svg) ![](doc/img/pp-scripts.svg)
## Examples ## Examples
The [source code](pp.md) of this document contains some diagrams. The [source code](pp.md) of this document contains some diagrams.
skipping to change at line 760 skipping to change at line 860
O -> B O -> B
O -> C O -> C
O -> D O -> D
D -> O D -> O
A -> B A -> B
B -> C B -> C
C -> A C -> A
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- `twopi` is the kind of graph (possible graph types: `dot`, `neato`, - `twopi` is the kind of graph (possible graph types: `dot`, `neato`,
`twopi`, `circo`, `fdp`, `sfdp`, `patchwork`). `twopi`, `circo`, `fdp`, `sfdp`, `patchwork`).
- `doc/img/pp-graphviz-example` is the name of the image. `pp` will - `doc/img/pp-graphviz-example` is the name of the image. `pp` will
generate `doc/img/pp-graphviz-example.dot` and generate `doc/img/pp-graphviz-example.dot` and
`doc/img/pp-graphviz-example.png`. `doc/img/pp-graphviz-example.png`.
- the rest of the first line is the legend of the graph. - the rest of the first line is the legend of the graph.
- other lines are written to `doc/img/pp-graphviz-example.dot` before - other lines are written to `doc/img/pp-graphviz-example.dot` before
running [Graphviz](http://graphviz.org/). running [Graphviz](http://graphviz.org/).
other lines are written to `doc/img/pp-graphviz-example.dot` before - if the command line argument `-img=prefix`, `prefix` is added at the
- if the command line argument `-img=prefix`, `prefix` is added at the
beginning of the image path. beginning of the image path.
if the command line argument `-img=prefix`, `prefix` is added at the
Once generated the graph looks like: Once generated the graph looks like:
![This is just a GraphViz diagram ![This is just a GraphViz diagram
example](doc/img/pp-graphviz-example.svg) example](doc/img/pp-graphviz-example.svg)
[GraphViz](http://graphviz.org/) must be installed. [GraphViz](http://graphviz.org/) must be installed.
### PlantUML ### PlantUML
skipping to change at line 891 skipping to change at line 991
// Affichage des trois vecteurs dans le repère R // Affichage des trois vecteurs dans le repère R
point RpM=changecoordsys(R, pM); point RpM=changecoordsys(R, pM);
show(Label("$\vec{f}$",EndPoint),RpM+vfrottement); show(Label("$\vec{f}$",EndPoint),RpM+vfrottement);
show(Label("$\vec{R}$",EndPoint),RpM+vreactionN); show(Label("$\vec{R}$",EndPoint),RpM+vreactionN);
show(Label("$\vec{P}$",EndPoint),RpM+vpoids); show(Label("$\vec{P}$",EndPoint),RpM+vpoids);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once generated the figure looks like: Once generated the figure looks like:
![This is just an Asymptote example from <figure>
<http://asy.marris.fr/asymptote/Sciences_physiques/index.html>](doc/img/pp-asy-e <img src="doc/img/pp-asy-example.svg" style="width:50.0%" alt="This is just an A
xample.svg) symptote example from http://asy.marris.fr/asymptote/Sciences_physiques/index.ht
ml" /><figcaption aria-hidden="true">This is just an Asymptote example from <a h
ref="http://asy.marris.fr/asymptote/Sciences_physiques/index.html" class="uri">h
ttp://asy.marris.fr/asymptote/Sciences_physiques/index.html</a></figcaption>
</figure>
**Note**: Asymptote handles transparency in PDF format only, which is **Note**: Asymptote handles transparency in PDF format only, which is
converted to PNG by `pp`. If you need transparency, you must use the converted to PNG by `pp`. If you need transparency, you must use the
`.png` or `pdf` format (PNG images are generated by converting the PDF `.png` or `pdf` format (PNG images are generated by converting the PDF
output of Asymptote). If you need scalable images, you must use the output of Asymptote). If you need scalable images, you must use the
`.svg` format, which is the default format for Asymptote diagrams. `.svg` format, which is the default format for Asymptote diagrams.
### R (plot) ### R (plot)
[R](https://www.r-project.org/) is executed when the keyword `Rplot` is [R](https://www.r-project.org/) is executed when the keyword `Rplot` is
skipping to change at line 928 skipping to change at line 1029
!bash !bash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
echo "Hi, I'm $SHELL $BASH_VERSION" echo "Hi, I'm $SHELL $BASH_VERSION"
RANDOM=42 # seed RANDOM=42 # seed
echo "Here are a few random numbers: $RANDOM, $RANDOM, $RANDOM" echo "Here are a few random numbers: $RANDOM, $RANDOM, $RANDOM"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script outputs: This script outputs:
Hi, I'm bash 5.1.0(1)-release Hi, I'm bash 5.1.8(1)-release
Here are a few random numbers: 17772, 26794, 1435 Here are a few random numbers: 17772, 26794, 1435
**Note**: the keyword `sh` executes `sh` which is generally a link to **Note**: the keyword `sh` executes `sh` which is generally a link to
`bash`. `bash`.
### Cmd
Windows’ [command-line
interpreter](https://en.wikipedia.org/wiki/Cmd.exe) is executed when the
keyword `cmd` is used.
!cmd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
echo Hi, I'm %COMSPEC%
ver
if "%WINELOADER%%WINELOADERNOEXEC%%WINEDEBUG%" == "" (
echo This script is run from wine under Linux
) else (
echo This script is run from a real Windows
)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script outputs:
Hi, I'm C:\windows\system32\cmd.exe
Microsoft Windows 6.1.7601
This script is run from a real Windows
### Python ### Python
[Python](https://www.python.org/) is executed when the keyword `python` [Python](https://www.python.org/) is executed when the keyword `python`
is used. is used.
!python !python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import sys import sys
import random import random
if __name__ == "__main__": if __name__ == "__main__":
print("Hi, I'm Python %s"%sys.version) print("Hi, I'm Python %s"%sys.version)
random.seed(42) random.seed(42)
randoms = [random.randint(0, 1000) for i in range(3)] randoms = [random.randint(0, 1000) for i in range(3)]
print("Here are a few random numbers: %s"%(", ".join(map(str, randoms))) ) print("Here are a few random numbers: %s"%(", ".join(map(str, randoms))) )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script outputs: This script outputs:
Hi, I'm Python 3.9.5 (default, May 14 2021, 00:00:00) Hi, I'm Python 3.10.0 (default, Oct 4 2021, 00:00:00) [GCC 11.2.1 20210728
[GCC 11.1.1 20210428 (Red Hat 11.1.1-1)] (Red Hat 11.2.1-1)]
Here are a few random numbers: 654, 114, 25 Here are a few random numbers: 654, 114, 25
### Lua ### Lua
[Lua](http://www.lua.org/) is executed when the keyword `lua` is used. [Lua](http://www.lua.org/) is executed when the keyword `lua` is used.
!lua !lua
~~~~~ ~~~~~
print("Hi, I'm ".._VERSION) print("Hi, I'm ".._VERSION)
math.randomseed(42) math.randomseed(42)
skipping to change at line 1011 skipping to change at line 1135
The first 10 prime numbers are: 2 3 5 7 11 13 17 19 23 29 The first 10 prime numbers are: 2 3 5 7 11 13 17 19 23 29
### Stack ### Stack
[Haskell](https://www.haskell.org/) is also executed when the keyword [Haskell](https://www.haskell.org/) is also executed when the keyword
`stack` is used. In this case stack meta data must be added at the `stack` is used. In this case stack meta data must be added at the
beginning of the script. beginning of the script.
!stack !stack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{- stack script --resolver lts-18.0 --package base -} {- stack script --resolver lts-18.17 --package base -}
import System.Info import System.Info
import Data.Version import Data.Version
import Data.List import Data.List
primes = filterPrime [2..] primes = filterPrime [2..]
where filterPrime (p:xs) = where filterPrime (p:xs) =
p : filterPrime [x | x <- xs, x `mod` p /= 0] p : filterPrime [x | x <- xs, x `mod` p /= 0]
version = showVersion compilerVersion version = showVersion compilerVersion
skipping to change at line 1047 skipping to change at line 1171
is used. is used.
!Rscript !Rscript
~~~~~ ~~~~~
model = lm(dist~speed, data = cars) model = lm(dist~speed, data = cars)
summary(model) summary(model)
~~~~~ ~~~~~
This script outputs: This script outputs:
``` Call:
lm(formula = dist ~ speed, data = cars)
Call:
lm(formula = dist ~ speed, data = cars)
Residuals: Residuals:
Min 1Q Median 3Q Max Min 1Q Median 3Q Max
-29.069 -9.525 -2.272 9.215 43.201 -29.069 -9.525 -2.272 9.215 43.201
Coefficients: Coefficients:
Estimate Std. Error t value Pr(>|t|) Estimate Std. Error t value Pr(>|t|)
(Intercept) -17.5791 6.7584 -2.601 0.0123 * (Intercept) -17.5791 6.7584 -2.601 0.0123 *
speed 3.9324 0.4155 9.464 1.49e-12 *** speed 3.9324 0.4155 9.464 1.49e-12 ***
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 ---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 15.38 on 48 degrees of freedom
Multiple R-squared: 0.6511, Adjusted R-squared: 0.6438 Residual standard error: 15.38 on 48 degrees of freedom
F-statistic: 89.57 on 1 and 48 DF, p-value: 1.49e-12 Multiple R-squared: 0.6511, Adjusted R-squared: 0.6438
``` F-statistic: 89.57 on 1 and 48 DF, p-value: 1.49e-12
# Mustache templates # Mustache templates
`pp` uses a builtin Haskell `pp` uses a builtin Haskell
[Mustache](https://github.com/JustusAdam/mustache) implementation that [Mustache](https://github.com/JustusAdam/mustache) implementation that
reads JSON or YAML files and generates text from a Mustache template. reads JSON or YAML files and generates text from a Mustache template.
[Mustache](https://github.com/JustusAdam/mustache) is executed when the [Mustache](https://github.com/JustusAdam/mustache) is executed when the
keyword `mustache` is used. keyword `mustache` is used.
!mustache(../package.yaml) !mustache(../package.yaml)
``````````````````````````````````````` ```````````````````````````````````````
This is the documentation for `{{name}}` version {{version}} by {{author}}. This is the documentation for `{{name}}` version {{version}} by {{author}}.
Copyright !bold({{copyright}}). Copyright !bold({{copyright}}).
``````````````````````````````````````` ```````````````````````````````````````
`package.yaml` contains: `package.yaml` contains:
name: pp name: pp
version: "2.14.2" version: "2.14.3"
github: "CDSoft/pp" github: "CDSoft/pp"
license: GPL-3 license: GPL-3
author: "Christophe Delord" author: "Christophe Delord"
maintainer: "cdelord.fr" maintainer: "cdelord.fr"
copyright: "2015-2020 Christophe Delord" copyright: "2015-2021 Christophe Delord"
Lambdas are not supported but the template is preprocessed by `pp` Lambdas are not supported but the template is preprocessed by `pp`
before calling Mustache. E.g. `!bold` can be defined as before calling Mustache. E.g. `!bold` can be defined as
`!def(bold)(**!1**)`. These “*lambda macros*” can be defined in the `!def(bold)(**!1**)`. These “*lambda macros*” can be defined in the
YAML/JSON data file as well, which is a non standard way to define YAML/JSON data file as well, which is a non standard way to define
Mustache lambdas that works with `pp` only. Mustache lambdas that works with `pp` only.
This outputs: This outputs:
This is the documentation for `pp` version 2.14.2 by Christophe Delord. This is the documentation for `pp` version 2.14.3 by Christophe Delord.
Copyright **2015-2020 Christophe Delord**. Copyright **2015-2021 Christophe Delord**.
# CSV tables # CSV tables
CSV files can be included in documents and rendered as Markdown or CSV files can be included in documents and rendered as Markdown or
reStructuredText tables. The field separator is inferred from the reStructuredText tables. The field separator is inferred from the
content of the file. It can be a comma, a semicolon, tabulation or a content of the file. It can be a comma, a semicolon, tabulation or a
pipe. pipe.
## Files with a header line ## Files with a header line
skipping to change at line 1124 skipping to change at line 1245
Year,Make,Model,Description,Price Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00 1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00 1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00 1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! 1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00 air, moon roof, loaded",4799.00
is rendered by `!csv(file.csv)` as: is rendered by `!csv(file.csv)` as:
| Year | Make | Model | Description | Year | Make | Model | Description
| Price | | Price |
| ---: | :---- | :------------------------------------- | :--------------------- |-----:|:------|:---------------------------------------|:----------------------
------------ | ------: | ------------|--------:|
| 1997 | Ford | E350 | ac, abs, moon | 1997 | Ford | E350 | ac, abs, moon
| 3000.00 | | 3000.00 |
| 1999 | Chevy | Venture “Extended Edition” | | 1999 | Chevy | Venture “Extended Edition” |
| 4900.00 | | 4900.00 |
| 1999 | Chevy | Venture “Extended Edition, Very Large” | | 1999 | Chevy | Venture “Extended Edition, Very Large” |
| 5000.00 | | 5000.00 |
| 1996 | Jeep | Grand Cherokee | MUST SELL\! air, moon | 1996 | Jeep | Grand Cherokee | MUST SELL! air, moon r
roof, loaded | 4799.00 | oof, loaded | 4799.00 |
## Files without any header line ## Files without any header line
This file: This file:
1997,Ford,E350,"ac, abs, moon",3000.00 1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00 1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00 1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! 1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799.00 air, moon roof, loaded",4799.00
is rendered by `!csv(file.csv)(Year|Make|Model|Description|Price)` as: is rendered by `!csv(file.csv)(Year|Make|Model|Description|Price)` as:
| Year | Make | Model | Description | Year | Make | Model | Description
| Price | | Price |
| ---: | :---- | :------------------------------------- | :--------------------- |-----:|:------|:---------------------------------------|:----------------------
------------ | ------: | ------------|--------:|
| 1997 | Ford | E350 | ac, abs, moon | 1997 | Ford | E350 | ac, abs, moon
| 3000.00 | | 3000.00 |
| 1999 | Chevy | Venture “Extended Edition” | | 1999 | Chevy | Venture “Extended Edition” |
| 4900.00 | | 4900.00 |
| 1999 | Chevy | Venture “Extended Edition, Very Large” | | 1999 | Chevy | Venture “Extended Edition, Very Large” |
| 5000.00 | | 5000.00 |
| 1996 | Jeep | Grand Cherokee | MUST SELL\! air, moon | 1996 | Jeep | Grand Cherokee | MUST SELL! air, moon r
roof, loaded | 4799.00 | oof, loaded | 4799.00 |
# OS support # OS support
PP is meant to be portable and multi platform. To be OS agnostic, the PP is meant to be portable and multi platform. To be OS agnostic, the
use of free script languages is strongly recommended. For instance, bash use of free script languages is strongly recommended. For instance, bash
scripts are preferred to proprietary closed languages because they can scripts are preferred to proprietary closed languages because they can
run on any platform. It is standard on Linux and pretty well supported run on any platform. It is standard on Linux and pretty well supported
on Windows (Cygwin, MSYS/Mingw, Git Bash, BusyBox, …). Python is also a on Windows (Cygwin, MSYS/Mingw, Git Bash, BusyBox, …). Python is also a
good choice. good choice.
skipping to change at line 1187 skipping to change at line 1308
!linux(Hello, happy GNU/Linux user) !linux(Hello, happy GNU/Linux user)
The `!exec` macro is also OS aware. It runs the *default* shell The `!exec` macro is also OS aware. It runs the *default* shell
according to the OS (`sh` on Linux and MacOS, `cmd` on Windows). according to the OS (`sh` on Linux and MacOS, `cmd` on Windows).
# Tests # Tests
`make test` will test most of pp capabilities. They have been designed `make test` will test most of pp capabilities. They have been designed
to run on Linux and require a bunch of softwares: to run on Linux and require a bunch of softwares:
- a decent Linux distribution - a decent Linux distribution
- [Stack](https://docs.haskellstack.org/en/stable/README/) - [Stack](https://docs.haskellstack.org/en/stable/README/)
- [Pandoc](http://pandoc.org/) - [Pandoc](http://pandoc.org/)
- [Meld](https://meldmerge.org/) - [Meld](https://meldmerge.org/)
- [Bash](https://www.gnu.org/software/bash/), - [Bash](https://www.gnu.org/software/bash/),
[zsh](http://www.zsh.org/), [fish](https://fishshell.com/) [zsh](http://www.zsh.org/), [fish](https://fishshell.com/)
[Bash](https://www.gnu.org/software/bash/), - [Wine](https://www.winehq.org/)
- [Wine](https://www.winehq.org/) - [Python](https://www.python.org/)
- [Python](https://www.python.org/) - [Lua](http://www.lua.org/)
- [Lua](http://www.lua.org/) - [GraphViz](http://graphviz.org/)
- [GraphViz](http://graphviz.org/) - [Asymptote](http://asymptote.sourceforge.net/)
- [Asymptote](http://asymptote.sourceforge.net/) - [R](https://www.r-project.org/)
- [R](https://www.r-project.org/) - [Haskell](https://www.haskell.org/)
- [Haskell](https://www.haskell.org/) - [blockdiag](http://blockdiag.com/)
- [blockdiag](http://blockdiag.com/) - [gcc](https://gcc.gnu.org/)
- [gcc](https://gcc.gnu.org/) - … and everything I have forgotten
- … and everything I have forgotten
… and everything I have forgotten
*note*: blockdiag is written in Python. According to your Python *note*: blockdiag is written in Python. According to your Python
version, scripts may or may not be suffixed by `2` or `3`. In this case, version, scripts may or may not be suffixed by `2` or `3`. In this case,
you may have to add appropriate links: you may have to add appropriate links:
>
>
> ``` sh > ``` sh
> sudo ln -vs /usr/bin/blockdiag3 /usr/bin/blockdiag > sudo ln -vs /usr/bin/blockdiag3 /usr/bin/blockdiag
> sudo ln -vs /usr/bin/seqdiag3 /usr/bin/seqdiag > sudo ln -vs /usr/bin/seqdiag3 /usr/bin/seqdiag
> sudo ln -vs /usr/bin/actdiag3 /usr/bin/actdiag > sudo ln -vs /usr/bin/actdiag3 /usr/bin/actdiag
> sudo ln -vs /usr/bin/nwdiag3 /usr/bin/nwdiag > sudo ln -vs /usr/bin/nwdiag3 /usr/bin/nwdiag
> sudo ln -vs /usr/bin/rackdiag3 /usr/bin/rackdiag > sudo ln -vs /usr/bin/rackdiag3 /usr/bin/rackdiag
> sudo ln -vs /usr/bin/packetdiag3 /usr/bin/packetdiag > sudo ln -vs /usr/bin/packetdiag3 /usr/bin/packetdiag
> ``` > ```
Some tests may fail if the script interpreters’ versions are different. Some tests may fail if the script interpreters’ versions are different.
`make ref` will open `meld` to show the differences and fix the expected `make ref` will open `meld` to show the differences and fix the expected
results. results.
# Third-party documentations, tutorials and macros # Third-party documentations, tutorials and macros
- [PP - [PP
tutorial](https://github.com/tajmone/markdown-guide/tree/master/pp) tutorial](https://github.com/tajmone/markdown-guide/tree/master/pp)
by [tajmone](https://github.com/tajmone): a good starting point for by [tajmone](https://github.com/tajmone): a good starting point for
beginners. beginners.
- [Pandoc-Goodies PP-Macros - [Pandoc-Goodies PP-Macros
Library](https://github.com/tajmone/pandoc-goodies/tree/master/pp) Library](https://github.com/tajmone/pandoc-goodies/tree/master/pp)
by [tajmone](https://github.com/tajmone): an ongoing collaborative by [tajmone](https://github.com/tajmone): an ongoing collaborative
effort to build a library of PP macros. effort to build a library of PP macros.
# Licenses # Licenses
## PP ## PP
Copyright (C) 2015-2020 Christophe Delord <br> <http://cdelord.fr/pp> Copyright (C) 2015-2021 Christophe Delord <br> <http://cdelord.fr/pp>
PP is free software: you can redistribute it and/or modify it under the PP 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 terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your Software Foundation, either version 3 of the License, or (at your
option) any later version. option) any later version.
PP is distributed in the hope that it will be useful, but WITHOUT ANY PP is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details. more details.
 End of changes. 65 change blocks. 
485 lines changed or deleted 598 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)