initial import
21
LICENSE
Executable file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2010, Troy Hanson http://tpl.sourceforge.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
2
Makefile.am
Normal file
@ -0,0 +1,2 @@
|
||||
SUBDIRS = src
|
||||
EXTRA_DIST = LICENSE tests lang doc
|
56
README
Normal file
@ -0,0 +1,56 @@
|
||||
tpl: fast, easy serialization in C
|
||||
==============================================================================
|
||||
|
||||
Documentation for tpl is available in the doc/ directory or at:
|
||||
|
||||
http://tpl.sourceforge.net
|
||||
|
||||
You can build tpl as a library, like so:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
This installs libtpl.so and libtpl.a into a standard system library directory.
|
||||
You can customize the install directory using configure's "--prefix" option:
|
||||
|
||||
./configure --prefix=/some/directory
|
||||
|
||||
For other options accepted by configure, run "./configure --help".
|
||||
|
||||
NON-LIBRARY OPTION
|
||||
------------------
|
||||
Alternatively, if you don't want to muck around with libraries, you can simply
|
||||
copy these two files into your own C project and build them with your program:
|
||||
|
||||
src/tpl.h
|
||||
src/tpl.c
|
||||
|
||||
WINDOWS
|
||||
-------
|
||||
You can build tpl as a DLL under Visual Studio 2008. Or you can use MinGW or
|
||||
Cygwin.
|
||||
|
||||
SELF-TEST SUITE
|
||||
---------------
|
||||
The automated self-test can be run by doing:
|
||||
|
||||
cd tests
|
||||
make
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
The BSD license applies to this software. The text is in the LICENSE file.
|
||||
|
||||
CREDITS
|
||||
-------
|
||||
Many people have contributed to tpl, both bits of code and ideas. Rather than
|
||||
listing them all here, at risk of omitting anyone- I just wish to say thank
|
||||
you. Some particular features are noted with contributors' names in the
|
||||
ChangeLog.
|
||||
|
||||
Feel free to send me questions, comments or bug reports.
|
||||
|
||||
Troy D. Hanson, February 5, 2010
|
||||
thanson@users.sourceforge.net
|
||||
|
11
bootstrap
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# THIS SCRIPT IS FOR PROJECT MAINTAINER ONLY
|
||||
# It is executed only to generate "configure"
|
||||
|
||||
set -x
|
||||
aclocal -I config
|
||||
autoheader
|
||||
libtoolize --copy --force
|
||||
automake --foreign --add-missing --copy
|
||||
autoconf
|
28
configure.ac
Normal file
@ -0,0 +1,28 @@
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
AC_INIT([libtpl], [1.4], [thanson@users.sourceforge.net])
|
||||
AC_CONFIG_SRCDIR(src/tpl.c)
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
AC_CONFIG_HEADERS(config/config.h)
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_PROG_CC
|
||||
dnl next 4 lines are a hack to avoid libtool's
|
||||
dnl needless checks for C++ and Fortran compilers
|
||||
m4_undefine([AC_PROG_CXX])
|
||||
m4_defun([AC_PROG_CXX],[])
|
||||
m4_undefine([AC_PROG_F77])
|
||||
m4_defun([AC_PROG_F77],[])
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
dnl detect Cygwin or MinGW and use mmap family replacements
|
||||
AC_CONFIG_LIBOBJ_DIR(src/win)
|
||||
case $host in
|
||||
*-*-mingw32* | *-*-cygwin* | *-*-windows*)
|
||||
AC_LIBOBJ(mmap)
|
||||
AC_MSG_NOTICE([using custom mmap for Cygwin/MinGW])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CONFIG_FILES(src/win/Makefile src/Makefile Makefile)
|
||||
AC_OUTPUT
|
||||
|
26
doc/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
all: css userguide pdf changelog perl
|
||||
|
||||
userguide: txt/userguide.txt
|
||||
asciidoc --unsafe --out-file=html/userguide.html -a linkcss=1 -a theme=tdh txt/userguide.txt
|
||||
|
||||
changelog: txt/ChangeLog.txt
|
||||
asciidoc --out-file=html/ChangeLog.html txt/ChangeLog.txt
|
||||
|
||||
.PHONY: pdf
|
||||
|
||||
pdf: txt/userguide.txt
|
||||
a2x -f pdf $<
|
||||
mv txt/userguide.pdf pdf/
|
||||
cd html && ln -sf ../pdf/userguide.pdf userguide.pdf
|
||||
rm -f txt/userguide.xml
|
||||
|
||||
perl: txt/perl.txt
|
||||
asciidoc --unsafe --out-file=html/perl.html -a linkcss=1 -a theme=tdh txt/perl.txt
|
||||
|
||||
css: html/toc.css
|
||||
cat /etc/asciidoc/stylesheets/xhtml11.css html/toc.css > html/tdh.css
|
||||
cp /etc/asciidoc/stylesheets/xhtml11-quirks.css html/tdh-quirks.css
|
||||
|
||||
docbook: txt/userguide.txt
|
||||
asciidoc -b docbook --out-file=/tmp/userguide.xml txt/userguide.txt
|
||||
xmlto -o html html-nochunks /tmp/userguide.xml
|
11
doc/NOTES
Normal file
@ -0,0 +1,11 @@
|
||||
# maintainer notes
|
||||
|
||||
# IE6 png gamma bug:
|
||||
# PNG images in IE6 display with wrong background colors,
|
||||
# solution: save PNG in Gimp *Without save gamma checked*
|
||||
|
||||
#update sourceforge web site:
|
||||
#cd html
|
||||
#scp *.{html,css} thanson@shell.sourceforge.net:/home/groups/t/tp/tpl/htdocs
|
||||
#cd img
|
||||
#scp *.png *.jpg thanson@shell.sourceforge.net:/home/groups/t/tp/tpl/htdocs/img
|
796
doc/html/ChangeLog.html
Normal file
@ -0,0 +1,796 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="generator" content="AsciiDoc 8.5.2" />
|
||||
<title>tpl ChangeLog</title>
|
||||
<style type="text/css">
|
||||
/* Debug borders */
|
||||
p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
|
||||
/*
|
||||
border: 1px solid red;
|
||||
*/
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 1em 5% 1em 5%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:visited {
|
||||
color: fuchsia;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
color: navy;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
color: #083194;
|
||||
}
|
||||
|
||||
tt {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
margin-top: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
h2 {
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
h3 {
|
||||
float: left;
|
||||
}
|
||||
h3 + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
div.sectionbody {
|
||||
font-family: serif;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
ul, ol, li > p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span#author {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
span#email {
|
||||
}
|
||||
span#revnumber, span#revdate, span#revremark {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div#footer {
|
||||
font-family: sans-serif;
|
||||
font-size: small;
|
||||
border-top: 2px solid silver;
|
||||
padding-top: 0.5em;
|
||||
margin-top: 4.0em;
|
||||
}
|
||||
div#footer-text {
|
||||
float: left;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
div#footer-badges {
|
||||
float: right;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
div#preamble {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
|
||||
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
|
||||
div.admonitionblock {
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
div.admonitionblock {
|
||||
margin-top: 2.0em;
|
||||
margin-bottom: 2.0em;
|
||||
margin-right: 10%;
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
div.content { /* Block element content. */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Block element titles. */
|
||||
div.title, caption.title {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
div.title + * {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
td div.title:first-child {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
div.content div.title:first-child {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
div.content + div.title {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
|
||||
div.sidebarblock > div.content {
|
||||
background: #ffffee;
|
||||
border: 1px solid silver;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.listingblock > div.content {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.quoteblock, div.verseblock {
|
||||
padding-left: 1.0em;
|
||||
margin-left: 1.0em;
|
||||
margin-right: 10%;
|
||||
border-left: 5px solid #dddddd;
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
div.quoteblock > div.attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock > div.content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock > div.attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
|
||||
div.verseblock + div.attribution {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.admonitionblock .icon {
|
||||
vertical-align: top;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
color: #527bbd;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
div.admonitionblock td.content {
|
||||
padding-left: 0.5em;
|
||||
border-left: 3px solid #dddddd;
|
||||
}
|
||||
|
||||
div.exampleblock > div.content {
|
||||
border-left: 3px solid #dddddd;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
div.imageblock div.content { padding-left: 0; }
|
||||
span.image img { border-style: none; }
|
||||
a.image:visited { color: white; }
|
||||
|
||||
dl {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
dt {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0;
|
||||
font-style: normal;
|
||||
color: navy;
|
||||
}
|
||||
dd > *:first-child {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
list-style-position: outside;
|
||||
}
|
||||
ol.arabic {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
ol.loweralpha {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
ol.upperalpha {
|
||||
list-style-type: upper-alpha;
|
||||
}
|
||||
ol.lowerroman {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
ol.upperroman {
|
||||
list-style-type: upper-roman;
|
||||
}
|
||||
|
||||
div.compact ul, div.compact ol,
|
||||
div.compact p, div.compact p,
|
||||
div.compact div, div.compact div {
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.tableblock > table {
|
||||
border: 3px solid #527bbd;
|
||||
}
|
||||
thead, p.table.header {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
tfoot {
|
||||
font-weight: bold;
|
||||
}
|
||||
td > div.verse {
|
||||
white-space: pre;
|
||||
}
|
||||
p.table {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Because the table frame attribute is overriden by CSS in most browsers. */
|
||||
div.tableblock > table[frame="void"] {
|
||||
border-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="hsides"] {
|
||||
border-left-style: none;
|
||||
border-right-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="vsides"] {
|
||||
border-top-style: none;
|
||||
border-bottom-style: none;
|
||||
}
|
||||
|
||||
|
||||
div.hdlist {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
div.hdlist tr {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
dt.hdlist1.strong, td.hdlist1.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
td.hdlist1 {
|
||||
vertical-align: top;
|
||||
font-style: normal;
|
||||
padding-right: 0.8em;
|
||||
color: navy;
|
||||
}
|
||||
td.hdlist2 {
|
||||
vertical-align: top;
|
||||
}
|
||||
div.hdlist.compact tr {
|
||||
margin: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.comment {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.footnote, .footnoteref {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
span.footnote, span.footnoteref {
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
#footnotes {
|
||||
margin: 20px 0 20px 0;
|
||||
padding: 7px 0 0 0;
|
||||
}
|
||||
|
||||
#footnotes div.footnote {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
#footnotes hr {
|
||||
border: none;
|
||||
border-top: 1px solid silver;
|
||||
height: 1px;
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
width: 20%;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
|
||||
@media print {
|
||||
div#footer-badges { display: none; }
|
||||
}
|
||||
|
||||
div#toc {
|
||||
margin-bottom: 2.5em;
|
||||
}
|
||||
|
||||
div#toctitle {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
div.toclevel2 {
|
||||
margin-left: 2em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
div.toclevel3 {
|
||||
margin-left: 4em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
div.toclevel4 {
|
||||
margin-left: 6em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
/* Workarounds for IE6's broken and incomplete CSS2. */
|
||||
|
||||
div.sidebar-content {
|
||||
background: #ffffee;
|
||||
border: 1px solid silver;
|
||||
padding: 0.5em;
|
||||
}
|
||||
div.sidebar-title, div.image-title {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
margin-top: 0.0em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
div.listingblock div.content {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.quoteblock-attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock-content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock-attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.exampleblock-content {
|
||||
border-left: 3px solid #dddddd;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
/* IE6 sets dynamically generated links as visited. */
|
||||
div#toc a:visited { color: blue; }
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
/*<![CDATA[*/
|
||||
window.onload = function(){asciidoc.footnotes();}
|
||||
var asciidoc = { // Namespace.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Table Of Contents generator
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Author: Mihai Bazon, September 2002
|
||||
* http://students.infoiasi.ro/~mishoo
|
||||
*
|
||||
* Table Of Content generator
|
||||
* Version: 0.4
|
||||
*
|
||||
* Feel free to use this script under the terms of the GNU General Public
|
||||
* License, as long as you do not remove or alter this notice.
|
||||
*/
|
||||
|
||||
/* modified by Troy D. Hanson, September 2006. License: GPL */
|
||||
/* modified by Stuart Rackham, 2006, 2009. License: GPL */
|
||||
|
||||
// toclevels = 1..4.
|
||||
toc: function (toclevels) {
|
||||
|
||||
function getText(el) {
|
||||
var text = "";
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
|
||||
text += i.data;
|
||||
else if (i.firstChild != null)
|
||||
text += getText(i);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function TocEntry(el, text, toclevel) {
|
||||
this.element = el;
|
||||
this.text = text;
|
||||
this.toclevel = toclevel;
|
||||
}
|
||||
|
||||
function tocEntries(el, toclevels) {
|
||||
var result = new Array;
|
||||
var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
|
||||
// Function that scans the DOM tree for header elements (the DOM2
|
||||
// nodeIterator API would be a better technique but not supported by all
|
||||
// browsers).
|
||||
var iterate = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
var mo = re.exec(i.tagName);
|
||||
if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
|
||||
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
|
||||
}
|
||||
iterate(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterate(el);
|
||||
return result;
|
||||
}
|
||||
|
||||
var toc = document.getElementById("toc");
|
||||
var entries = tocEntries(document.getElementById("content"), toclevels);
|
||||
for (var i = 0; i < entries.length; ++i) {
|
||||
var entry = entries[i];
|
||||
if (entry.element.id == "")
|
||||
entry.element.id = "_toc_" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + entry.element.id;
|
||||
a.appendChild(document.createTextNode(entry.text));
|
||||
var div = document.createElement("div");
|
||||
div.appendChild(a);
|
||||
div.className = "toclevel" + entry.toclevel;
|
||||
toc.appendChild(div);
|
||||
}
|
||||
if (entries.length == 0)
|
||||
toc.parentNode.removeChild(toc);
|
||||
},
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Footnotes generator
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Based on footnote generation code from:
|
||||
* http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
|
||||
*/
|
||||
|
||||
footnotes: function () {
|
||||
var cont = document.getElementById("content");
|
||||
var noteholder = document.getElementById("footnotes");
|
||||
var spans = cont.getElementsByTagName("span");
|
||||
var refs = {};
|
||||
var n = 0;
|
||||
for (i=0; i<spans.length; i++) {
|
||||
if (spans[i].className == "footnote") {
|
||||
n++;
|
||||
// Use [\s\S] in place of . so multi-line matches work.
|
||||
// Because JavaScript has no s (dotall) regex flag.
|
||||
note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
|
||||
noteholder.innerHTML +=
|
||||
"<div class='footnote' id='_footnote_" + n + "'>" +
|
||||
"<a href='#_footnoteref_" + n + "' title='Return to text'>" +
|
||||
n + "</a>. " + note + "</div>";
|
||||
spans[i].innerHTML =
|
||||
"[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
|
||||
"' title='View footnote' class='footnote'>" + n + "</a>]";
|
||||
var id =spans[i].getAttribute("id");
|
||||
if (id != null) refs["#"+id] = n;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
noteholder.parentNode.removeChild(noteholder);
|
||||
else {
|
||||
// Process footnoterefs.
|
||||
for (i=0; i<spans.length; i++) {
|
||||
if (spans[i].className == "footnoteref") {
|
||||
var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
|
||||
href = href.match(/#.*/)[0]; // Because IE return full URL.
|
||||
n = refs[href];
|
||||
spans[i].innerHTML =
|
||||
"[<a href='#_footnote_" + n +
|
||||
"' title='View footnote' class='footnote'>" + n + "</a>]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*]]>*/
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>tpl ChangeLog</h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
<h2 id="_version_1_6_2010">Version 1.6 (2010-??-??)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
Fixed a bug in the Windows version of tpl that prevented an application
|
||||
from serializing more than once to the same file- the file stayed locked until
|
||||
the application was closed. (thanks, Werner Krattenthaler!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Fixed a documentation error to indicate that <tt>tpl_dump</tt> when used in the
|
||||
<tt>TPL_GETSIZE</tt> mode stores its result in a <tt>size_t</tt> rather than a <tt>uint32_t</tt>
|
||||
(thanks, M. Nunberge!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Fixed a typo in the User Guide example of packing a linked link (thanks, Bryan Mishkin!)
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_5_2010_02_05">Version 1.5 (2010-02-05)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
tpl now builds as a DLL under Microsoft Visual Studio! (thanks, degski and Zhang Yafei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
there are now two download options: the <a href="http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2">tarball</a> and the Visual Studio <a href="http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip">solution</a>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
a crash in <tt>tpl_free</tt> on certain format strings has been fixed (thanks, Eric Rose!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fixed a bug in <tt>tpl_dump</tt> on 64-bit, big-endian platforms
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
changed some pointer casts from <tt>long</tt> to <tt>uintptr_t</tt> since 64-bit Windows has 32-bit longs
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
tpl has been downloaded 4,195 times.
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_4_2009_04_21">Version 1.4 (2009-04-21)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
fixed-length arrays can now be multi-dimensional like <tt>i##</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fixed-length string arrays like <tt>s#</tt> are now supported
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
nested structures can now be expressed, using the dollar symbol, e.g. <tt>S(ci$(cc))</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>tpl_dump</tt> can use a caller-allocated output buffer (<tt>TPL_MEM|TPL_PREALLOCD</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<tt>tpl_load</tt> can tolerate excess space in input buffer (<tt>TPL_MEM|TPL_EXCESS_OK</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
implement <tt>TPL_FXLENS</tt> flag for <tt>tpl_peek</tt> to get lengths of fixed-length arrays
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
implement <tt>TPL_GETSIZE</tt> flag for <tt>tpl_dump</tt> to get dump size without dumping
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
fix success return code from <tt>tpl_dump(TPL_FD,...)</tt> (thanks, Max Lapan!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
deprecated the wildcard unpacking <tt>S(*)</tt> feature
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_3_2009_02_10">Version 1.3 (2009-02-10)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
added <tt>TPL_DATAPEEK</tt> mode for <tt>tpl_peek</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for <tt>NULL</tt> strings
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for 16-bit integer types (<tt>j</tt>,<tt>v</tt>)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <tt>tpl_jot</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for fixed-length arrays of structures <tt>S(...)#</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added support for pre-C99 compilers (thanks, Wei Wei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
improved structure alignment calculation (thanks, Wu Yongwei!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added RPM spec file (thanks, Alessandro Ren!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
compiles cleanly with <tt>-Wall</tt> and <tt>-pedantic</tt> and with <tt>-O3</tt>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
made <a href="license.html">BSD license</a> terms even more permissive
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
test suite: exit with status zero when all tests pass
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added PDF user guide
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <a href="http://troydhanson.wordpress.com/feed/">update news</a> <span class="image">
|
||||
<img src="img/rss.png" alt="(RSS)" />
|
||||
</span>
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
added <a href="http://apps.sourceforge.net/mediawiki/tpl/">tpl wiki</a>
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_2_2007_04_27">Version 1.2 (2007-04-27)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
Perl API and XML converter support 64-bit types
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_1_2007_04_25">Version 1.1 (2007-04-25)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
support for serializing C structures
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
support for serializing fixed-length arrays
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
MinGW support (thanks, Horea Haitonic!)
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
revised User Guide
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
<h2 id="_version_1_0_2006_09_28">Version 1.0 (2006-09-28)</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist"><ul>
|
||||
<li>
|
||||
<p>
|
||||
Initial version
|
||||
</p>
|
||||
</li>
|
||||
</ul></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footnotes"><hr /></div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2011-04-27 22:45:54 EDT
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
BIN
doc/html/img/banner.png
Normal file
After Width: | Height: | Size: 24 KiB |
429
doc/html/img/banner.svg
Normal file
@ -0,0 +1,429 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="728px"
|
||||
height="90px"
|
||||
id="svg1323"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44"
|
||||
sodipodi:docbase="/home/thanson/code/tpl/trunk/doc/html/img"
|
||||
sodipodi:docname="banner.svg"
|
||||
inkscape:export-filename="/home/thanson/code/tpl/trunk/doc/html/img/banner.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs1325">
|
||||
<linearGradient
|
||||
id="linearGradient22211">
|
||||
<stop
|
||||
style="stop-color:#2e7ce0;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop22237" />
|
||||
<stop
|
||||
id="stop22215"
|
||||
offset="1"
|
||||
style="stop-color:#2e7ce0;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient20106">
|
||||
<stop
|
||||
style="stop-color:#f0f3f7;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop20108" />
|
||||
<stop
|
||||
style="stop-color:#f0f3f7;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop20110" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient19154">
|
||||
<stop
|
||||
style="stop-color:#005fd9;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19156" />
|
||||
<stop
|
||||
style="stop-color:#005fd9;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19158" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient19142">
|
||||
<stop
|
||||
style="stop-color:#4ec2f0;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19144" />
|
||||
<stop
|
||||
style="stop-color:#4ec2f0;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19146" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient19132">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop19134" />
|
||||
<stop
|
||||
id="stop19140"
|
||||
offset="0.5"
|
||||
style="stop-color:#00d1f6;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop19136" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19142"
|
||||
id="radialGradient19150"
|
||||
cx="651"
|
||||
cy="50"
|
||||
fx="651"
|
||||
fy="50"
|
||||
r="49.5"
|
||||
gradientTransform="matrix(1,0,0,0.616162,1.124101e-15,19.19192)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient19160"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient19224"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientTransform="matrix(5.590915,0,0,1.101015,-3310.4,161.4223)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient20106"
|
||||
id="radialGradient20112"
|
||||
cx="125.1579"
|
||||
cy="213.03658"
|
||||
fx="125.1579"
|
||||
fy="213.03658"
|
||||
r="27.577164"
|
||||
gradientTransform="matrix(1,0,0,0.923077,0,16.38742)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20176"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47"
|
||||
gradientTransform="translate(-38.18377,318.1981)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20203"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-38.18377,318.1981)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20269"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-38.18377,318.1981)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient20389"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1053.937,335.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient22243"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.867037,0,0,1.101015,-1120.758,425.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient24137"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1052.937,435.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient19154"
|
||||
id="linearGradient24144"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.755096,0,0,1.101015,-1049.937,270.4223)"
|
||||
x1="588"
|
||||
y1="47"
|
||||
x2="722"
|
||||
y2="47" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="497.48754"
|
||||
inkscape:cy="-4.5816549"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="1176"
|
||||
inkscape:window-height="633"
|
||||
inkscape:window-x="23"
|
||||
inkscape:window-y="48" />
|
||||
<metadata
|
||||
id="metadata1328">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="fill:#3c85e2;fill-opacity:1;fill-rule:nonzero;stroke:#ffcb53;stroke-width:4.0415926;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect20271"
|
||||
width="240.0993"
|
||||
height="77.071068"
|
||||
x="4.1015167"
|
||||
y="3.6345825"
|
||||
rx="29.60623" />
|
||||
<rect
|
||||
y="46.014687"
|
||||
x="-236.92256"
|
||||
height="16.982321"
|
||||
width="16.982321"
|
||||
id="rect24091"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
y="46.014687"
|
||||
x="-219.80927"
|
||||
height="16.982321"
|
||||
width="16.982321"
|
||||
id="rect24093"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect24095"
|
||||
width="16.982321"
|
||||
height="16.982321"
|
||||
x="-202.92258"
|
||||
y="46.014687"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e33019;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24097"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
transform="translate(-102.0443,123.8305)" />
|
||||
<path
|
||||
transform="translate(-76.04438,87.8305)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e38c19;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24099"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
transform="translate(-64.0444,105.8305)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#88dfdb;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24101"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24103"
|
||||
style="fill:#79c71a;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="translate(-76.04438,123.8305)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24105"
|
||||
style="fill:#f5e1a2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="translate(-88.04433,105.8305)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24107"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,460.1983,124.4007)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24109"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,442.9488,124.4007)" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,426.1983,124.4007)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24111"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 146.68046,40.305464 L 153.06062,49.875694"
|
||||
id="path24113"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 146.68046,31.875694 L 153.06062,22.305464"
|
||||
id="path24115"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;marker-end:none;stroke-opacity:1"
|
||||
d="M 158.68046,22.305464 L 165.06062,31.875694"
|
||||
id="path24117"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 224.06859,54.660809 L 215.24887,54.660809"
|
||||
id="path24119"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 206.81911,54.660809 L 198.49837,54.660809"
|
||||
id="path24121"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 140.5923,40.305464 L 133.14878,49.875694"
|
||||
id="path24123"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 198.08195,67.740894 L 198.08195,67.740894"
|
||||
id="path24125"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24127"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-1,0,0,1,410.1983,124.4007)" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path24129"
|
||||
d="M 190.81911,54.660809 L 182.49837,54.660809"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 170.23387,40.305398 L 175.92003,50.445833"
|
||||
id="path24131"
|
||||
inkscape:connector-type="polyline" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:57.24448395px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:2.58558559px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono"
|
||||
x="13.482153"
|
||||
y="61.413116"
|
||||
id="text24133"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24135"
|
||||
x="13.482153"
|
||||
y="61.413116"
|
||||
style="font-size:57.24448395px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono">tpl</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:33.35416794px;font-style:normal;font-weight:normal;fill:#ff8900;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
x="313.95825"
|
||||
y="31.16275"
|
||||
id="text24140"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24142"
|
||||
x="313.95825"
|
||||
y="31.16275"
|
||||
style="stroke:none;stroke-opacity:1">easily store and retrieve </tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="313.95825"
|
||||
y="72.85546"
|
||||
style="font-weight:bold;stroke:none;stroke-opacity:1"
|
||||
id="tspan1941">binary data in C</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="313.95825"
|
||||
y="114.54817"
|
||||
style="stroke:none;stroke-opacity:1"
|
||||
id="tspan1939" /></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 17 KiB |
BIN
doc/html/img/grad_azure.png
Normal file
After Width: | Height: | Size: 409 B |
105
doc/html/img/grad_azure.svg
Normal file
@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.43"
|
||||
sodipodi:docbase="/home/thanson/code/tpl/doc/html/img"
|
||||
sodipodi:docname="grad_cyan.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient2194">
|
||||
<stop
|
||||
style="stop-color:#1190ed;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2196" />
|
||||
<stop
|
||||
style="stop-color:#f9f9f9;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2198" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2184">
|
||||
<stop
|
||||
style="stop-color:#0000e0;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2186" />
|
||||
<stop
|
||||
style="stop-color:#0000e0;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2184"
|
||||
id="linearGradient2190"
|
||||
x1="76.642857"
|
||||
y1="679.50504"
|
||||
x2="523.35714"
|
||||
y2="679.50504"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2194"
|
||||
id="linearGradient2200"
|
||||
x1="335.5"
|
||||
y1="654.61218"
|
||||
x2="506"
|
||||
y2="654.61218"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2"
|
||||
inkscape:cx="488.2215"
|
||||
inkscape:cy="372.85714"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="797"
|
||||
inkscape:window-height="575"
|
||||
inkscape:window-x="112"
|
||||
inkscape:window-y="25" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:0.96629214;fill:url(#linearGradient2200);fill-opacity:1.0;stroke:none;stroke-width:4.68499994;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2192"
|
||||
width="170.5"
|
||||
height="9.5"
|
||||
x="335.5"
|
||||
y="649.86218"
|
||||
inkscape:export-filename="/home/thanson/code/tpl/doc/html/img/grad_cyan.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
BIN
doc/html/img/rss.png
Executable file
After Width: | Height: | Size: 689 B |
BIN
doc/html/img/tpl-mini.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
242
doc/html/img/tpl-mini.svg
Normal file
@ -0,0 +1,242 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="105.05521"
|
||||
height="34.90324"
|
||||
id="svg2267"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/thanson/code/uthash/trunk/doc/html/img"
|
||||
sodipodi:docname="tpl-mini.svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="63.027613"
|
||||
inkscape:cy="11.686998"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
width="118.44px"
|
||||
height="22.66px"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="916"
|
||||
inkscape:window-height="626"
|
||||
inkscape:window-x="15"
|
||||
inkscape:window-y="95">
|
||||
<sodipodi:guide
|
||||
orientation="horizontal"
|
||||
position="28.768574"
|
||||
id="guide2299" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2271">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-69.67658,-43.42744)">
|
||||
<rect
|
||||
style="fill:#3c85e2;fill-opacity:1;fill-rule:nonzero;stroke:#ffcb53;stroke-width:1.73912036;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect20271"
|
||||
width="103.31609"
|
||||
height="33.16412"
|
||||
x="70.546143"
|
||||
y="44.296997"
|
||||
rx="12.739729" />
|
||||
<rect
|
||||
y="62.533398"
|
||||
x="-170.73035"
|
||||
height="7.3075895"
|
||||
width="7.3075895"
|
||||
id="rect24091"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
y="62.533398"
|
||||
x="-163.36638"
|
||||
height="7.3075895"
|
||||
width="7.3075895"
|
||||
id="rect24093"
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
transform="scale(-1,1)" />
|
||||
<rect
|
||||
style="fill:#2fa4db;fill-opacity:1;stroke:black;stroke-width:0.43030569;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect24095"
|
||||
width="7.3075895"
|
||||
height="7.3075895"
|
||||
x="-156.09996"
|
||||
y="62.533398"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e33019;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24097"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
transform="matrix(0.430306,0,0,0.430306,24.87099,96.01799)" />
|
||||
<path
|
||||
transform="matrix(0.430306,0,0,0.430306,36.05889,80.52698)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#e38c19;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24099"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
transform="matrix(0.430306,0,0,0.430306,41.22256,88.27247)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#88dfdb;fill-opacity:1;fill-rule:nonzero;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24101"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24103"
|
||||
style="fill:#79c71a;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(0.430306,0,0,0.430306,36.05889,96.01799)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24105"
|
||||
style="fill:#f5e1a2;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(0.430306,0,0,0.430306,30.89524,88.27247)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24107"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,266.8073,96.26334)" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24109"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,259.3847,96.26334)" />
|
||||
<path
|
||||
transform="matrix(-0.430306,0,0,0.430306,252.1769,96.26334)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path24111"
|
||||
sodipodi:cx="231.91481"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:ry="3.7148824"
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 131.89866,60.076683 L 134.64408,64.194808"
|
||||
id="path24113"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 131.89866,56.449305 L 134.64408,52.33118"
|
||||
id="path24115"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;marker-end:none;stroke-opacity:1"
|
||||
d="M 137.06234,52.33118 L 139.80775,56.449305"
|
||||
id="path24117"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 165.19922,66.25387 L 161.40404,66.25387"
|
||||
id="path24119"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 157.77667,66.25387 L 154.19622,66.25387"
|
||||
id="path24121"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 129.2789,60.076683 L 126.07591,64.194808"
|
||||
id="path24123"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 154.01702,71.882304 L 154.01702,71.882304"
|
||||
id="path24125"
|
||||
inkscape:connector-type="polyline" />
|
||||
<path
|
||||
d="M 235.62969 -69.739944 A 3.7148824 3.7148824 0 1 1 228.19993,-69.739944 A 3.7148824 3.7148824 0 1 1 235.62969 -69.739944 z"
|
||||
sodipodi:ry="3.7148824"
|
||||
sodipodi:rx="3.7148824"
|
||||
sodipodi:cy="-69.739944"
|
||||
sodipodi:cx="231.91481"
|
||||
id="path24127"
|
||||
style="fill:#d8643e;fill-opacity:1;stroke:black;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
sodipodi:type="arc"
|
||||
transform="matrix(-0.430306,0,0,0.430306,245.292,96.26334)" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path24129"
|
||||
d="M 150.89178,66.25387 L 147.31131,66.25387"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:0.43030569px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 142.03383,60.076654 L 144.48062,64.440141"
|
||||
id="path24131"
|
||||
inkscape:connector-type="polyline" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:24.63262939px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:1.11259222px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono"
|
||||
x="74.58268"
|
||||
y="69.159424"
|
||||
id="text24133"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan24135"
|
||||
x="74.58268"
|
||||
y="69.159424"
|
||||
style="font-size:24.63262939px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ff8900;fill-opacity:1;stroke:#ffc900;stroke-width:1.11259222;stroke-opacity:0.95530725;font-family:Bitstream Vera Sans Mono">tpl</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/html/img/tpl.dia
Normal file
BIN
doc/html/img/tpl.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
doc/html/img/tpl_aai.dia
Normal file
162
doc/html/index.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>tpl home page</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="img/banner.png" alt="easy data storage and retrieval in C" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
tpl home
|
||||
</div> <!-- topnav -->
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
|
||||
<div id="nav">
|
||||
|
||||
|
||||
<h2>documentation</h2>
|
||||
<div><a href="userguide.html">user guide</a> (<a href="userguide.html">html</a>, <a href="userguide.pdf">pdf</a>)</div>
|
||||
|
||||
<h2>download</h2>
|
||||
<h3>Linux, Mac OSX, Solaris, BSD</h3>
|
||||
<div><a href="http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2">libtpl-1.5.tar.bz2</a></div>
|
||||
<h3>Visual Studio 2008 Solution</h3>
|
||||
<div><a href="http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip">tpl-1.5-vs2008.zip</a></div>
|
||||
|
||||
<h2>last release</h2>
|
||||
<div>February, 2010</div>
|
||||
<div><a href="ChangeLog.html">ChangeLog</a></div>
|
||||
|
||||
<h2>license</h2>
|
||||
<div><a href="license.html">BSD revised</a></div>
|
||||
|
||||
<h2>news feed</h2>
|
||||
<div><a href="http://troydhanson.wordpress.com/">updates blog</a> (<a href="http://troydhanson.wordpress.com/feed/">rss</a>)<img alt=" rss" src="img/rss.png"/></div>
|
||||
|
||||
<h2>platforms</h2>
|
||||
<div>linux</div>
|
||||
<div>os x</div>
|
||||
<div>windows</div>
|
||||
<div>solaris</div>
|
||||
<div>openbsd</div>
|
||||
|
||||
<h2>other projects</h2>
|
||||
<div><a href="http://uthash.sourceforge.net/">uthash</a></div>
|
||||
<div><a href="http://tkhanson.net/misc/">scripts & snippets</a></div>
|
||||
|
||||
<h2>developer</h2>
|
||||
<div>Troy D. Hanson</div>
|
||||
<div>tdh at tkhanson.net</div>
|
||||
|
||||
</div> <!-- nav -->
|
||||
|
||||
<div id="main">
|
||||
|
||||
<div>
|
||||
<div class="lead">Efficient serialization in C</div>
|
||||
You can use tpl to store and reload your C data quickly and easily.
|
||||
Tpl works with files, memory buffers and file descriptors so it's
|
||||
suitable for use as a file format, IPC message format or any scenario
|
||||
where you need to store and retrieve your data.
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="lead">Express your data</div>
|
||||
Just express the type of data you are working with as a tpl format string. For
|
||||
example, if you have a list of numeric ids and corresponding usernames, your
|
||||
format string is <em>A(is)</em>. Map your C variables to the format string and
|
||||
then pack or unpack data. The format string lets you focus on your data,
|
||||
rather than the storage format.
|
||||
</div>
|
||||
|
||||
<div class="listing">
|
||||
<table summary="example of storing and reloading an integer array">
|
||||
<tr>
|
||||
<th>
|
||||
Storing ids and usernames
|
||||
</th>
|
||||
<th>
|
||||
Reloading ids and usernames
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#include "tpl.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tpl_node *tn;
|
||||
int id=0;
|
||||
char *name, *names[] = { "joe", "bob", "cary" };
|
||||
|
||||
tn = tpl_map("A(is)", &id, &name);
|
||||
|
||||
for(name=names[0]; id < 3; name=names[++id]) {
|
||||
tpl_pack(tn,1);
|
||||
}
|
||||
|
||||
tpl_dump(tn, TPL_FILE, "users.tpl");
|
||||
tpl_free(tn);
|
||||
}
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</td>
|
||||
<td>
|
||||
<div class="code">
|
||||
<pre>
|
||||
#include "tpl.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tpl_node *tn;
|
||||
int id;
|
||||
char *name;
|
||||
|
||||
tn = tpl_map("A(is)", &id, &name);
|
||||
tpl_load(tn, TPL_FILE, "users.tpl");
|
||||
|
||||
while ( tpl_unpack(tn,1) > 0 ) {
|
||||
printf("id %d, user %s\n", id, name);
|
||||
free(name);
|
||||
}
|
||||
tpl_free(tn);
|
||||
}
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- listing -->
|
||||
|
||||
<div>
|
||||
<div class="lead">No library dependencies</div>
|
||||
Tpl does not make your software dependent on any libraries. You can compile its
|
||||
source code (one file) right into your program.
|
||||
</div>
|
||||
|
||||
<div class="lead">For more information</div>
|
||||
For a more thorough explanation and more examples, please read the
|
||||
<a href="userguide.html">User Guide.</a>
|
||||
|
||||
</div> <!-- main -->
|
||||
</div> <!-- mid -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
<a href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=13" width="120" height="30" alt="SourceForge.net." /></a>
|
||||
<p>This project is hosted on SourceForge.net</p>
|
||||
<p>$Id: index.html 192 2009-04-24 10:35:30Z thanson $</p>
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
61
doc/html/license.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>tpl home page</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="img/banner.png" alt="serialization in C: easy data storage and retrieval" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a href="index.html">tpl home</a> >
|
||||
BSD license
|
||||
</div> <!-- topnav -->
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
<pre>
|
||||
Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre>
|
||||
</div> <!-- main -->
|
||||
</div> <!-- mid -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
<a href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=13" width="120" height="30" alt="SourceForge.net." /></a>
|
||||
<p>This project is hosted on SourceForge.net</p>
|
||||
<p>$Id: index.html 124 2007-04-27 06:41:36Z thanson $</p>
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
412
doc/html/perl.html
Normal file
@ -0,0 +1,412 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="generator" content="AsciiDoc 8.5.2" />
|
||||
<title>tpl Perl API</title>
|
||||
<link rel="stylesheet" href="./tdh.css" type="text/css" />
|
||||
<link rel="stylesheet" href="./tdh-quirks.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
/*<![CDATA[*/
|
||||
window.onload = function(){asciidoc.footnotes();}
|
||||
/*]]>*/
|
||||
</script>
|
||||
<script type="text/javascript" src="./asciidoc-xhtml11.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1>tpl Perl API</h1>
|
||||
<span id="author">Troy D. Hanson</span><br />
|
||||
<span id="email"><tt><<a href="mailto:troydhanson@comcast.net">troydhanson@comcast.net</a>></tt></span><br />
|
||||
<span id="revnumber">version 1.1,</span>
|
||||
<span id="revdate">April 2007</span>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<a style="float: right;" href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=16" width="150" height="40" alt="SourceForge.net" /></a>
|
||||
<div id="topnav" style="font-size: 9pt; font-family: sans-serif;">
|
||||
<a style="padding: 8px;" href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a style="padding: 8px;" href="index.html">tpl home</a> >
|
||||
tpl Perl API
|
||||
<a style="padding: 8px;" href="userguide.pdf">[View PDF]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="_perl_api">Perl API</h2>
|
||||
<div class="sectionbody">
|
||||
<div id="toc"></div>
|
||||
<script>
|
||||
window.onload=generate_TOC
|
||||
|
||||
/* Author: Mihai Bazon, September 2002
|
||||
* <a href="http://students.infoiasi.ro/~mishoo">http://students.infoiasi.ro/~mishoo</a>
|
||||
*
|
||||
* Table Of Content generator
|
||||
* Version: 0.4
|
||||
*
|
||||
* Feel free to use this script under the terms of the GNU General Public
|
||||
* License, as long as you do not remove or alter this notice.
|
||||
*/
|
||||
|
||||
/* modified by Troy D. Hanson, September 2006. License: GPL */
|
||||
|
||||
function H_getText(el) {
|
||||
var text = "";
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 3 /* Node.TEXT_NODE, IE doesn't speak constants */)
|
||||
text += i.data;
|
||||
else if (i.firstChild != null)
|
||||
text += H_getText(i);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function TOC_EL(el, text, level) {
|
||||
this.element = el;
|
||||
this.text = text;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
function getHeadlines(el) {
|
||||
var l = new Array;
|
||||
var rx = /[hH]([2-3])/;
|
||||
// internal recursive function that scans the DOM tree
|
||||
var rec = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
if (rx.exec(i.tagName))
|
||||
l[l.length] = new TOC_EL(i, H_getText(i), parseInt(RegExp.$1));
|
||||
rec(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
rec(el);
|
||||
return l;
|
||||
}
|
||||
|
||||
function generate_TOC() {
|
||||
var parent = document.getElementById("toc");
|
||||
var toc_hdr = document.createElement("div");
|
||||
var toc_hdr_txt = document.createTextNode("CONTENTS");
|
||||
toc_hdr.appendChild(toc_hdr_txt);
|
||||
/* toc_hdr.setAttribute("id","hdr"); */
|
||||
toc_hdr.id = "hdr";
|
||||
parent.appendChild(toc_hdr);
|
||||
var hs = getHeadlines(document.getElementsByTagName("body")[0]);
|
||||
for (var i = 0; i < hs.length; ++i) {
|
||||
var hi = hs[i];
|
||||
var d = document.createElement("div");
|
||||
if (hi.element.id == "") hi.element.id = "gen" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + hi.element.id;
|
||||
a.appendChild(document.createTextNode(hi.text));
|
||||
d.appendChild(a);
|
||||
d.className = "level" + hi.level;
|
||||
parent.appendChild(d);
|
||||
/*
|
||||
if (hi.level == 3) {
|
||||
var dvtop = document.createElement("div");
|
||||
dvtop.className = "toplink";
|
||||
dvtop.appendChild(document.createTextNode("^top^"));
|
||||
dvtop.onclick=function(){scrollTo(0,0);};
|
||||
hi.element.appendChild(dvtop);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div class="paragraph"><p>The Perl API for reading and writing tpl is nearly identical to the C API. This
|
||||
document will briefly explain the Perl API and provide examples. The chief
|
||||
motivation for having a Perl API is to communicate with C programs that use tpl.</p></div>
|
||||
<div class="admonitionblock">
|
||||
<table><tr>
|
||||
<td class="icon">
|
||||
<div class="title">Tip</div>
|
||||
</td>
|
||||
<td class="content">
|
||||
<div class="title">Start with the C API</div>This document assumes familiarity with the C API. The concepts of using tpl
|
||||
are not explained here. For an introduction to tpl and its C API, see the
|
||||
<a href="userguide.html">User Guide</a>.</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<h3 id="_tpl_pm">Tpl.pm</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>The <tt>Tpl.pm</tt> file (in the <tt>lang/perl</tt>) directory contains the Perl module. You
|
||||
can copy it to another directory if you wish. Your Perl program may need to
|
||||
include a <tt>use lib</tt> statement to find the module.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
use lib "/some/directory";
|
||||
use Tpl;</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_map">tpl_map</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This function resembles the C version, except that it’s invoked via the <tt>Tpl</tt>
|
||||
module, and it takes references to Perl variables after the format string.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The return value is a tpl object; all other API calls are object methods.
|
||||
Incidentally, there is no <tt>tpl_free()</tt> method corresponding to the C API.</p></div>
|
||||
<h4 id="_fixed_length_arrays">Fixed-length arrays</h4>
|
||||
<div class="paragraph"><p>Format strings such as <tt>i#</tt> denote a fixed-length array. In the Perl API,
|
||||
fixed-length arrays require two arguments: a list reference, and the fixed
|
||||
length. For example:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my @x;
|
||||
my $tpl = Tpl->tpl_map("i#", \@x, 10);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>When fixed-length arrays are packed or unpacked, the specified number of
|
||||
elements will be copied from (or placed into) the designated list.</p></div>
|
||||
<h4 id="_structures">Structures</h4>
|
||||
<div class="paragraph"><p>Format strings containing <tt>S(...)</tt> are handled in the Perl API as if only the
|
||||
interior, parenthesized part was present. (It does not work like the C API). So
|
||||
simply ignore the <tt>S(...)</tt> and consider only its interior format characters when
|
||||
constructing the argument list:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my ($str, $int);
|
||||
my $tpl = Tpl->tpl_map("S(si)", \$str, \$int);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>It really only makes sense to use <tt>S(...)</tt> in a format string in the Perl API if
|
||||
you are communicating with a C program that uses structures.</p></div>
|
||||
<h3 id="_tpl_pack">tpl_pack</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This is nearly identical to the C version. The only argument is the index
|
||||
number to pack.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_pack(1);</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_dump">tpl_dump</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This method is a little different than the C version. Given no arguments, it
|
||||
returns the tpl image; given one argument it writes a file with that name.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_dump("demo.tpl"); # writes demo.tpl</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Or,</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>my $img = $tpl->tpl_dump();</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The tpl image is a binary buffer. You can do whatever you want with it, such as
|
||||
write it to a socket or pipe (probably to C program listening on the other end),
|
||||
or save it somewhere and later re-load it using <tt>tpl_load()</tt>.</p></div>
|
||||
<h3 id="_tpl_load">tpl_load</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This method loads a tpl image from a file or from a Perl variable. It takes
|
||||
one argument. If it’s not a reference, it’s assumed to be a filename to load.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_load("demo.tpl");</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Otherwise, if the argument is a Perl reference, it’s construed as a variable
|
||||
containing the tpl image:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_load(\$img);</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The method will <tt>die</tt> if the image is invalid or the file doesn’t exist. You
|
||||
can wrap it with <tt>eval</tt> to catch such errors:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>eval { $tpl->tpl_load(\$img); };
|
||||
print "failed to load\n" if $@;</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_tpl_unpack">tpl_unpack</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>This is nearly identical to the C version. The only argument is the index
|
||||
number to unpack.</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>$tpl->tpl_unpack(1);</tt></pre>
|
||||
</div></div>
|
||||
</div>
|
||||
<h2 id="_examples">Examples</h2>
|
||||
<div class="sectionbody">
|
||||
<h3 id="_integer_array">Integer array</h3><div style="clear:left"></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Packing A(i) to file</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) {
|
||||
$tpl->tpl_pack(1);
|
||||
}
|
||||
$tpl->tpl_dump("demo.tpl");</tt></pre>
|
||||
</div></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Unpacking A(i) from file</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Tpl;
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(i)",\$j);
|
||||
$tpl2->tpl_load("demo.tpl");
|
||||
while($tpl2->tpl_unpack(1) > 0) {
|
||||
print "$j\n";
|
||||
}</tt></pre>
|
||||
</div></div>
|
||||
<h3 id="_message_passing">Message-passing</h3><div style="clear:left"></div>
|
||||
<div class="paragraph"><p>While the bulk of this example is socket handling, it demonstrates how you can
|
||||
use tpl as a message-passing format. In the real-world, you might have a C
|
||||
server and a Perl client, for example. In this example, we’ll code both a client
|
||||
and a server in Perl.</p></div>
|
||||
<div class="sidebarblock">
|
||||
<div class="sidebar-content">
|
||||
<div class="sidebar-title">A server that sums integers</div>
|
||||
<div class="paragraph"><p>Programming literature is rife with contrived examples so we will follow in that
|
||||
tradition. Our server will do no more than sum a list of integers. But in doing
|
||||
so it will demonstrate message passing adequately. Both its input (the integer
|
||||
array) and its output (an integer) are tpl images, passed over a TCP/IP socket.</p></div>
|
||||
</div></div>
|
||||
<h4 id="_server">Server</h4>
|
||||
<div class="paragraph"><p>The server waits for a connection from a client. When it gets one, it accepts
|
||||
the connection and immediately forks a child process to handle it. Then it goes
|
||||
back to waiting for another new connection.</p></div>
|
||||
<div class="paragraph"><p>The server child process handles the client by loading and unpacking the tpl
|
||||
image sent by the client (containing an array of integers). It calculates their
|
||||
sum and constructs a new tpl image containing the sum, which it sends back to
|
||||
the client.</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Server</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use Tpl;
|
||||
|
||||
$SIG{CHLD} = "IGNORE"; # don't create zombies
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
sub handle_client {
|
||||
my $client = shift;
|
||||
|
||||
undef $/;
|
||||
my $request = <$client>; # get request (slurp)
|
||||
|
||||
# read input array, and calculate total
|
||||
my ($i,$total);
|
||||
my $tpl = Tpl->tpl_map("A(i)", \$i);
|
||||
eval { $tpl->tpl_load(\$request); };
|
||||
die "received invalid tpl" if $@;
|
||||
$total += $i while $tpl->tpl_unpack(1) > 0;
|
||||
|
||||
# formulate response and send
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
$tpl2->tpl_pack(0);
|
||||
my $response = $tpl2->tpl_dump();
|
||||
print $client $response;
|
||||
close $client;
|
||||
}
|
||||
|
||||
my $server = IO::Socket::INET->new(LocalPort => $port,
|
||||
Type => SOCK_STREAM,
|
||||
Reuse => 1,
|
||||
Listen => 10 )
|
||||
or die "Can't listen on port $port: $!\n";
|
||||
|
||||
while (1) {
|
||||
my $client = $server->accept();
|
||||
next unless $client;
|
||||
# new connection
|
||||
my $pid = fork;
|
||||
die "can't fork: $!\n" unless defined $pid;
|
||||
if ($pid > 0) {
|
||||
# parent
|
||||
close $client;
|
||||
} elsif ($pid == 0) {
|
||||
# child
|
||||
handle_client($client);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
close ($server);</tt></pre>
|
||||
</div></div>
|
||||
<h4 id="_client">Client</h4>
|
||||
<div class="paragraph"><p>The client is a simpler program. It constructs the tpl image containing the
|
||||
integer array (taken from its command-line arguments), connects to the server
|
||||
and sends the tpl image to it, and then awaits the response tpl. The response
|
||||
containing the sum is loaded, unpacked and printed.</p></div>
|
||||
<div class="listingblock">
|
||||
<div class="title">Client</div>
|
||||
<div class="content">
|
||||
<pre><tt>#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use Tpl;
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
# construct tpl
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
$tpl->tpl_pack(1) while ($i=shift @ARGV);
|
||||
my $request = $tpl->tpl_dump();
|
||||
|
||||
# send to server, get response
|
||||
my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect";
|
||||
print $socket $request;
|
||||
shutdown($socket,1); # done writing (half-close)
|
||||
undef $/;
|
||||
my $response = <$socket>; # get reply (slurp)
|
||||
|
||||
# decode response (or print error)
|
||||
my $total;
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
eval { $tpl2->tpl_load(\$response); };
|
||||
die "invalid response\n" if $@;
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "total is $total\n";</tt></pre>
|
||||
</div></div>
|
||||
<h4 id="_running_thise_example">Running thise example</h4>
|
||||
<div class="paragraph"><p>If the client and server programs are in <tt>client.pl</tt> and <tt>server.pl</tt>, then
|
||||
you can run the example by starting the server in one window:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>./server.pl</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>Then run the client in another window. E.g.,</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>./client.pl 1 2 3 4 5</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>The client runs and then exits, printing:</p></div>
|
||||
<div class="literalblock">
|
||||
<div class="content">
|
||||
<pre><tt>total is 15</tt></pre>
|
||||
</div></div>
|
||||
<div class="paragraph"><p>You can re-run the client with different arguments. When done, type <tt>Ctrl-C</tt> in
|
||||
the server window to terminate it.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footnotes"><hr /></div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Version 1.1<br />
|
||||
Last updated 2010-07-18 21:14:17 EDT
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
160
doc/html/styles.css
Normal file
@ -0,0 +1,160 @@
|
||||
#banner {
|
||||
/* font-size: x-large; */
|
||||
/* background: #ff00ff; */
|
||||
/* height: 100px; */
|
||||
}
|
||||
|
||||
#topnav {
|
||||
/* background-image: url(img/grad_topnav.png); */
|
||||
/* background-repeat: repeat-y; */
|
||||
/* background-color: #af00af; */
|
||||
/* height: 25px; */
|
||||
margin: 10px 0px 10px 20px;
|
||||
padding: 3px;
|
||||
font-size: 9pt;
|
||||
font-family: sans-serif;
|
||||
/* border-style: solid; */
|
||||
/* border-width: 1px; */
|
||||
}
|
||||
|
||||
|
||||
#topnav {font-weight: bold}
|
||||
#topnav a {font-weight: normal}
|
||||
|
||||
h1,p { margin: 0; } /* non-0 margin on firefox */
|
||||
|
||||
#mid {
|
||||
background-image: url(img/grad_azure.png);
|
||||
background-repeat: repeat-y;
|
||||
/* background-color: #ffddaa; */
|
||||
padding-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#mid img {
|
||||
padding-left: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: 0
|
||||
}
|
||||
|
||||
#nav {
|
||||
background-color: #fff8f1;
|
||||
margin-left: 10px;
|
||||
margin-top: 20px;
|
||||
float: left;
|
||||
padding: 10px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
|
||||
#nav h2 {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#nav h3 {
|
||||
/* font-weight: bold; */
|
||||
padding-left: 5px;
|
||||
/* font-style: oblique; */
|
||||
font-family: sans-serif;
|
||||
font-size: 7pt;
|
||||
}
|
||||
|
||||
#nav div {
|
||||
font-size: 9pt;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#main {
|
||||
background: #ffffff;
|
||||
margin-top: 20px;
|
||||
margin-left: 170px;
|
||||
padding-left: 20px;
|
||||
height: 100%;
|
||||
/* font-family: sans-serif; */
|
||||
}
|
||||
|
||||
#main h1 {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.listing {
|
||||
margin: 20px;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.code {
|
||||
padding: 10px;
|
||||
background: #f3f3f3;
|
||||
font-size: 8pt;
|
||||
font-weight: normal;
|
||||
width: 80%;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.code pre {
|
||||
padding-left: 20px;
|
||||
padding-right: 80px;
|
||||
}
|
||||
|
||||
#formatstrings {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
/* background: #00ffff; */
|
||||
margin-top: 5px;
|
||||
font-size: small;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
em {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0.04em;
|
||||
background: black;
|
||||
margin: 0 10% 0 0;
|
||||
}
|
||||
|
||||
#footer img {
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-family: sans-serif;
|
||||
font-size: larger;
|
||||
font-weight: bold;
|
||||
/* font-style: oblique; */
|
||||
margin: 30px 30px 30px 0px;
|
||||
color: #1122dd;
|
||||
}
|
||||
|
||||
ol {
|
||||
font-family: monospace;
|
||||
background: #dddddd;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
width: 80%;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
|
||||
#main #portrait {
|
||||
float: right;
|
||||
font-size: smaller;
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
41
doc/html/tdh-quirks.css
Normal file
@ -0,0 +1,41 @@
|
||||
/* Workarounds for IE6's broken and incomplete CSS2. */
|
||||
|
||||
div.sidebar-content {
|
||||
background: #ffffee;
|
||||
border: 1px solid silver;
|
||||
padding: 0.5em;
|
||||
}
|
||||
div.sidebar-title, div.image-title {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
margin-top: 0.0em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
div.listingblock div.content {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.quoteblock-attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock-content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock-attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.exampleblock-content {
|
||||
border-left: 3px solid #dddddd;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
/* IE6 sets dynamically generated links as visited. */
|
||||
div#toc a:visited { color: blue; }
|
402
doc/html/tdh.css
Normal file
@ -0,0 +1,402 @@
|
||||
/* Debug borders */
|
||||
p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
|
||||
/*
|
||||
border: 1px solid red;
|
||||
*/
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 1em 5% 1em 5%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:visited {
|
||||
color: fuchsia;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
color: navy;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
color: #083194;
|
||||
}
|
||||
|
||||
tt {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
margin-top: 1.2em;
|
||||
margin-bottom: 0.5em;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
h2 {
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
h3 {
|
||||
float: left;
|
||||
}
|
||||
h3 + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
div.sectionbody {
|
||||
font-family: serif;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid silver;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
ul, ol, li > p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span#author {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
span#email {
|
||||
}
|
||||
span#revnumber, span#revdate, span#revremark {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div#footer {
|
||||
font-family: sans-serif;
|
||||
font-size: small;
|
||||
border-top: 2px solid silver;
|
||||
padding-top: 0.5em;
|
||||
margin-top: 4.0em;
|
||||
}
|
||||
div#footer-text {
|
||||
float: left;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
div#footer-badges {
|
||||
float: right;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
div#preamble {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
|
||||
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
|
||||
div.admonitionblock {
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
div.admonitionblock {
|
||||
margin-top: 2.0em;
|
||||
margin-bottom: 2.0em;
|
||||
margin-right: 10%;
|
||||
color: #606060;
|
||||
}
|
||||
|
||||
div.content { /* Block element content. */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Block element titles. */
|
||||
div.title, caption.title {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
div.title + * {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
td div.title:first-child {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
div.content div.title:first-child {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
div.content + div.title {
|
||||
margin-top: 0.0em;
|
||||
}
|
||||
|
||||
div.sidebarblock > div.content {
|
||||
background: #ffffee;
|
||||
border: 1px solid silver;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.listingblock > div.content {
|
||||
border: 1px solid silver;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
div.quoteblock, div.verseblock {
|
||||
padding-left: 1.0em;
|
||||
margin-left: 1.0em;
|
||||
margin-right: 10%;
|
||||
border-left: 5px solid #dddddd;
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
div.quoteblock > div.attribution {
|
||||
padding-top: 0.5em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.verseblock > div.content {
|
||||
white-space: pre;
|
||||
}
|
||||
div.verseblock > div.attribution {
|
||||
padding-top: 0.75em;
|
||||
text-align: left;
|
||||
}
|
||||
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
|
||||
div.verseblock + div.attribution {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.admonitionblock .icon {
|
||||
vertical-align: top;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
color: #527bbd;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
div.admonitionblock td.content {
|
||||
padding-left: 0.5em;
|
||||
border-left: 3px solid #dddddd;
|
||||
}
|
||||
|
||||
div.exampleblock > div.content {
|
||||
border-left: 3px solid #dddddd;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
div.imageblock div.content { padding-left: 0; }
|
||||
span.image img { border-style: none; }
|
||||
a.image:visited { color: white; }
|
||||
|
||||
dl {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
dt {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0;
|
||||
font-style: normal;
|
||||
color: navy;
|
||||
}
|
||||
dd > *:first-child {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
list-style-position: outside;
|
||||
}
|
||||
ol.arabic {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
ol.loweralpha {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
ol.upperalpha {
|
||||
list-style-type: upper-alpha;
|
||||
}
|
||||
ol.lowerroman {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
ol.upperroman {
|
||||
list-style-type: upper-roman;
|
||||
}
|
||||
|
||||
div.compact ul, div.compact ol,
|
||||
div.compact p, div.compact p,
|
||||
div.compact div, div.compact div {
|
||||
margin-top: 0.1em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.tableblock > table {
|
||||
border: 3px solid #527bbd;
|
||||
}
|
||||
thead, p.table.header {
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
tfoot {
|
||||
font-weight: bold;
|
||||
}
|
||||
td > div.verse {
|
||||
white-space: pre;
|
||||
}
|
||||
p.table {
|
||||
margin-top: 0;
|
||||
}
|
||||
/* Because the table frame attribute is overriden by CSS in most browsers. */
|
||||
div.tableblock > table[frame="void"] {
|
||||
border-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="hsides"] {
|
||||
border-left-style: none;
|
||||
border-right-style: none;
|
||||
}
|
||||
div.tableblock > table[frame="vsides"] {
|
||||
border-top-style: none;
|
||||
border-bottom-style: none;
|
||||
}
|
||||
|
||||
|
||||
div.hdlist {
|
||||
margin-top: 0.8em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
div.hdlist tr {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
dt.hdlist1.strong, td.hdlist1.strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
td.hdlist1 {
|
||||
vertical-align: top;
|
||||
font-style: normal;
|
||||
padding-right: 0.8em;
|
||||
color: navy;
|
||||
}
|
||||
td.hdlist2 {
|
||||
vertical-align: top;
|
||||
}
|
||||
div.hdlist.compact tr {
|
||||
margin: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.comment {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
.footnote, .footnoteref {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
span.footnote, span.footnoteref {
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
#footnotes {
|
||||
margin: 20px 0 20px 0;
|
||||
padding: 7px 0 0 0;
|
||||
}
|
||||
|
||||
#footnotes div.footnote {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
#footnotes hr {
|
||||
border: none;
|
||||
border-top: 1px solid silver;
|
||||
height: 1px;
|
||||
text-align: left;
|
||||
margin-left: 0;
|
||||
width: 20%;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
|
||||
@media print {
|
||||
div#footer-badges { display: none; }
|
||||
}
|
||||
|
||||
div#toc {
|
||||
margin-bottom: 2.5em;
|
||||
}
|
||||
|
||||
div#toctitle {
|
||||
color: #527bbd;
|
||||
font-family: sans-serif;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 1.0em;
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
div.toclevel2 {
|
||||
margin-left: 2em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
div.toclevel3 {
|
||||
margin-left: 4em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
div.toclevel4 {
|
||||
margin-left: 6em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
#toc {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
border: 1px solid #000;
|
||||
margin: 0px 0px 20px 20px;
|
||||
padding: 0px;
|
||||
background: #f0f0f0;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#toc #hdr {
|
||||
color:#ffffff;
|
||||
background:#98b1c4;
|
||||
text-align:center;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: 0
|
||||
}
|
||||
|
||||
#toc a:visited, #toc a:link { color:#000; text-decoration: none }
|
||||
#toc a:hover { color:#00f; text-decoration: underline; }
|
||||
|
||||
#toc .level2 { margin-left: 1em; margin-top: 2px; margin-bottom: 2px; text-decoration: underline; }
|
||||
#toc .level3 { margin-left: 2em; font-size: 0.8em }
|
||||
|
||||
.toplink {
|
||||
float: right;
|
||||
font-size: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#topnav {font-weight: bold}
|
||||
#topnav a {font-weight: normal}
|
35
doc/html/toc.css
Normal file
@ -0,0 +1,35 @@
|
||||
#toc {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
border: 1px solid #000;
|
||||
margin: 0px 0px 20px 20px;
|
||||
padding: 0px;
|
||||
background: #f0f0f0;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
#toc #hdr {
|
||||
color:#ffffff;
|
||||
background:#98b1c4;
|
||||
text-align:center;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: 0
|
||||
}
|
||||
|
||||
#toc a:visited, #toc a:link { color:#000; text-decoration: none }
|
||||
#toc a:hover { color:#00f; text-decoration: underline; }
|
||||
|
||||
#toc .level2 { margin-left: 1em; margin-top: 2px; margin-bottom: 2px; text-decoration: underline; }
|
||||
#toc .level3 { margin-left: 2em; font-size: 0.8em }
|
||||
|
||||
.toplink {
|
||||
float: right;
|
||||
font-size: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#topnav {font-weight: bold}
|
||||
#topnav a {font-weight: normal}
|
1548
doc/html/userguide.html
Normal file
BIN
doc/pdf/userguide.pdf
Normal file
70
doc/txt/ChangeLog.txt
Normal file
@ -0,0 +1,70 @@
|
||||
tpl ChangeLog
|
||||
=============
|
||||
|
||||
Version 1.6 (2011-??-??)
|
||||
--------------------------
|
||||
* Added `const` to a number of API parameters and exposed tpl_map_va (thanks, Simon Dawson!)
|
||||
* Fixed a bug in the Windows version of tpl that prevented an application
|
||||
from serializing more than once to the same file- the file stayed locked until
|
||||
the application was closed. (thanks, Werner Krattenthaler!)
|
||||
* Fixed a documentation error to indicate that `tpl_dump` when used in the
|
||||
`TPL_GETSIZE` mode stores its result in a `size_t` rather than a `uint32_t`
|
||||
(thanks, M. Nunberge!)
|
||||
* Fixed a typo in the User Guide example of packing a linked link (thanks, Bryan Mishkin!)
|
||||
|
||||
Version 1.5 (2010-02-05)
|
||||
--------------------------
|
||||
* tpl now builds as a DLL under Microsoft Visual Studio! (thanks, degski and Zhang Yafei!)
|
||||
* there are now two download options: the http://downloads.sourceforge.net/tpl/libtpl-1.5.tar.bz2[tarball] and the Visual Studio http://downloads.sourceforge.net/tpl/tpl-1.5-vs2008.zip[solution]
|
||||
* a crash in `tpl_free` on certain format strings has been fixed (thanks, Eric Rose!)
|
||||
* fixed a bug in `tpl_dump` on 64-bit, big-endian platforms
|
||||
* changed some pointer casts from `long` to `uintptr_t` since 64-bit Windows has 32-bit longs
|
||||
* tpl has been downloaded 4,195 times.
|
||||
|
||||
|
||||
Version 1.4 (2009-04-21)
|
||||
--------------------------
|
||||
* fixed-length arrays can now be multi-dimensional like `i##`
|
||||
* fixed-length string arrays like `s#` are now supported
|
||||
* nested structures can now be expressed, using the dollar symbol, e.g. `S(ci$(cc))`
|
||||
* `tpl_dump` can use a caller-allocated output buffer (`TPL_MEM|TPL_PREALLOCD`)
|
||||
* `tpl_load` can tolerate excess space in input buffer (`TPL_MEM|TPL_EXCESS_OK`)
|
||||
* implement `TPL_FXLENS` flag for `tpl_peek` to get lengths of fixed-length arrays
|
||||
* implement `TPL_GETSIZE` flag for `tpl_dump` to get dump size without dumping
|
||||
* fix success return code from `tpl_dump(TPL_FD,...)` (thanks, Max Lapan!)
|
||||
* deprecated the wildcard unpacking `S(*)` feature
|
||||
|
||||
Version 1.3 (2009-02-10)
|
||||
--------------------------
|
||||
* added `TPL_DATAPEEK` mode for `tpl_peek`
|
||||
* added support for `NULL` strings
|
||||
* added support for 16-bit integer types (`j`,`v`)
|
||||
* added `tpl_jot`
|
||||
* added support for fixed-length arrays of structures `S(...)#`
|
||||
* added support for pre-C99 compilers (thanks, Wei Wei!)
|
||||
* improved structure alignment calculation (thanks, Wu Yongwei!)
|
||||
* added RPM spec file (thanks, Alessandro Ren!)
|
||||
* compiles cleanly with `-Wall` and `-pedantic` and with `-O3`
|
||||
* made link:license.html[BSD license] terms even more permissive
|
||||
* test suite: exit with status zero when all tests pass
|
||||
* added PDF user guide
|
||||
* added http://troydhanson.wordpress.com/feed/[update news] image:img/rss.png[(RSS)]
|
||||
* added http://apps.sourceforge.net/mediawiki/tpl/[tpl wiki]
|
||||
|
||||
Version 1.2 (2007-04-27)
|
||||
--------------------------
|
||||
* Perl API and XML converter support 64-bit types
|
||||
|
||||
Version 1.1 (2007-04-25)
|
||||
--------------------------
|
||||
* support for serializing C structures
|
||||
* support for serializing fixed-length arrays
|
||||
* MinGW support (thanks, Horea Haitonic!)
|
||||
* revised User Guide
|
||||
|
||||
Version 1.0 (2006-09-28)
|
||||
--------------------------
|
||||
* Initial version
|
||||
|
||||
// vim: set tw=80 wm=2 nowrap syntax=asciidoc:
|
||||
|
38
doc/txt/compiling.txt
Normal file
@ -0,0 +1,38 @@
|
||||
Compiling libtpl.a and libtpl.so
|
||||
--------------------------------
|
||||
|
||||
********************************************************************************
|
||||
Normally in the top-level directory you simply run:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
The rest of the document is not needed if you use this method.
|
||||
********************************************************************************
|
||||
|
||||
|
||||
Manual compilation of static and shared library on a GNU Linux system:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
First cd into the "src" directory.
|
||||
|
||||
Static library
|
||||
~~~~~~~~~~~~~~
|
||||
You can build the static library `libtpl.a` using these commands:
|
||||
|
||||
cc -c tpl.c
|
||||
ar rc libtpl.a tpl.o
|
||||
ranlib libtpl.a
|
||||
|
||||
Dynamic library
|
||||
~~~~~~~~~~~~~~
|
||||
You can build the dynamic library `libtpl.so` using these commands:
|
||||
|
||||
cc -fpic -c tpl.c
|
||||
cc -shared -o libtpl.so tpl.o
|
||||
|
||||
Keep in mind that you need to set the `LD_LIBRARY_PATH` environment variable
|
||||
to include the directory where `libtpl.so` is installed in order for your
|
||||
program to run. Alternatively you can put `libtpl.so` in a standard place like
|
||||
`/usr/lib` and regenerate `ld.so.cache` using `ldconfig`.
|
297
doc/txt/examples.txt
Normal file
@ -0,0 +1,297 @@
|
||||
tpl examples
|
||||
============
|
||||
Troy D. Hanson <troydhanson@comcast.net>>
|
||||
v1.0, October 2006
|
||||
|
||||
include::sflogo.txt[]
|
||||
include::topnav.txt[]
|
||||
|
||||
Examples
|
||||
--------
|
||||
include::toc.txt[]
|
||||
|
||||
This document is a set of representative examples demonstrating how to use
|
||||
tpl. If you're looking for a more explanatory document, please read the
|
||||
link:userguide.html[User Guide].
|
||||
|
||||
An integer array
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.Storing an array of integers to file
|
||||
-------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
int i;
|
||||
|
||||
tn = tpl_map( "A(i)", &i );
|
||||
for( i=0; i<10; i++ ) {
|
||||
tpl_pack( tn, 1 );
|
||||
}
|
||||
tpl_dump( tn, TPL_FILE, "demo.tpl" );
|
||||
tpl_free( tn );
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
A program that unpacks this tpl data file is shown below.
|
||||
|
||||
.Re-reading an array of integers from file
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
int i;
|
||||
|
||||
tn = tpl_map( "A(i)", &i );
|
||||
tpl_load( tn, TPL_FILE, "demo.tpl" );
|
||||
while (tpl_unpack( tn, 1 ) > 0) {
|
||||
printf("%d ", i);
|
||||
}
|
||||
tpl_free( tn );
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
When run, this program prints:
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
|
||||
|
||||
A nested array
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.Packing nested arrays
|
||||
--------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
char c;
|
||||
tpl_node *tn;
|
||||
|
||||
tn = tpl_map("A(A(c))", &c);
|
||||
|
||||
for(c='a'; c<'c'; c++) tpl_pack(tn,2);
|
||||
tpl_pack(tn, 1);
|
||||
|
||||
for(c='1'; c<'4'; c++) tpl_pack(tn,2);
|
||||
tpl_pack(tn, 1);
|
||||
|
||||
tpl_dump(tn, TPL_FILE, "test40.tpl");
|
||||
tpl_free(tn);
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
This creates a nested array in which the parent has two elements: the first
|
||||
element is the two-element nested array 'a', 'b'; and the second element is
|
||||
the three-element nested array '1', '2', '3'.
|
||||
|
||||
.Unpacking nested arrays
|
||||
--------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
char c;
|
||||
tpl_node *tn;
|
||||
|
||||
tn = tpl_map("A(A(c))", &c);
|
||||
|
||||
tpl_load(tn, TPL_FILE, "test40.tpl");
|
||||
while (tpl_unpack(tn,1) > 0) {
|
||||
while (tpl_unpack(tn,2) > 0) printf("%c ",c);
|
||||
printf("\n");
|
||||
}
|
||||
tpl_free(tn);
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
When run, this program prints:
|
||||
|
||||
a b
|
||||
1 2 3
|
||||
|
||||
A string array
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.Packing a string array
|
||||
-------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
char *s;
|
||||
|
||||
tn = tpl_map( "A(s)", &s );
|
||||
|
||||
s = "bob";
|
||||
tpl_pack(tn, 1);
|
||||
|
||||
s = "betty";
|
||||
tpl_pack(tn, 1);
|
||||
|
||||
tpl_dump(tn, TPL_FILE, "strings.tpl");
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
.Unpacking a string array
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
char *s;
|
||||
|
||||
tn = tpl_map( "A(s)", &s );
|
||||
tpl_load( tn, TPL_FILE, "strings.tpl" );
|
||||
|
||||
while (tpl_unpack( tn, 1 ) > 0) {
|
||||
printf("%s\n", s);
|
||||
free(s); /* important! */
|
||||
}
|
||||
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
When run, this program prints:
|
||||
|
||||
bob
|
||||
betty
|
||||
|
||||
Integer/string pairs
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.Packing integer/string pairs
|
||||
-------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tpl_node *tn;
|
||||
int id;
|
||||
char *name, *names[] = { "joe", "bob", "mary" };
|
||||
|
||||
tn = tpl_map("A(is)", &id, &name);
|
||||
|
||||
for(id=0,name=names[id]; id < 3; name=names[++id])
|
||||
tpl_pack(tn,1);
|
||||
|
||||
tpl_dump(tn, TPL_FILE, "/tmp/test35.tpl");
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
.Unpacking integer/string pairs
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "tpl.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
tpl_node *tn;
|
||||
int id;
|
||||
char *name;
|
||||
|
||||
tn = tpl_map("A(is)", &id, &name);
|
||||
tpl_load(tn, TPL_FILE, "/tmp/test35.tpl");
|
||||
|
||||
while ( tpl_unpack(tn,1) > 0 )
|
||||
printf("id %d, user %s\n", id, name);
|
||||
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
When run, this program prints:
|
||||
|
||||
id 0, user joe
|
||||
id 1, user bob
|
||||
id 2, user mary
|
||||
|
||||
A binary buffer
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.Packing a binary buffer
|
||||
-------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
#include <sys/time.h>
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
tpl_bin tb;
|
||||
struct timeval tv; /* we'll pack this structure as raw binary */
|
||||
gettimeofday(&tv,NULL); /* populate the structure with some data */
|
||||
|
||||
tn = tpl_map( "B", &tb );
|
||||
tb.sz = sizeof(struct timeval);
|
||||
tb.addr = &tv;
|
||||
tpl_pack( tn, 0 );
|
||||
|
||||
tpl_dump(tn, TPL_FILE, "bin.tpl");
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
.Unpacking a binary buffer
|
||||
-------------------------------------------------------------------------------
|
||||
#include "tpl.h"
|
||||
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
tpl_bin tb;
|
||||
|
||||
tn = tpl_map( "B", &tb );
|
||||
tpl_load( tn, TPL_FILE, "bin.tpl" );
|
||||
|
||||
tpl_unpack( tn, 0 );
|
||||
printf("binary buffer of length %d at address %p\n", tb.sz, tb.addr);
|
||||
free(tb.addr); /* important! */
|
||||
|
||||
tpl_free(tn);
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Simple pipe IPC
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This is a simple example of inter-process communication (IPC) over a pipe.
|
||||
|
||||
.IPC over a pipe
|
||||
-------------------------------------------------------------------------------
|
||||
int main() {
|
||||
tpl_node *tn;
|
||||
unsigned i, sum=0;
|
||||
int fd[2], pid;
|
||||
|
||||
pipe(fd);
|
||||
if ( (pid = fork()) == 0) { /* child */
|
||||
|
||||
tn = tpl_map("A(u)",&i);
|
||||
tpl_load(tn, TPL_FD, fd[0]);
|
||||
while (tpl_unpack(tn,1) > 0) sum += i;
|
||||
tpl_free(tn);
|
||||
printf("sum is %d\n", sum);
|
||||
|
||||
} else if (pid > 0) { /* parent */
|
||||
|
||||
tn = tpl_map("A(u)",&i);
|
||||
for(i=0;i<10000;i++) tpl_pack(tn,1);
|
||||
tpl_dump(tn,TPL_FD, fd[1] );
|
||||
tpl_free(tn);
|
||||
|
||||
waitpid(pid,NULL,0);
|
||||
}
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The child unpacks the integers in the message, and sums them, printing:
|
||||
|
||||
49995000
|
||||
|
||||
The example above (with `#include` headers omitted here) is included in the
|
||||
file `tests/test28.c`.
|
52
doc/txt/future.txt
Normal file
@ -0,0 +1,52 @@
|
||||
For future reference these are some API design ideas- not working code!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Java API ideas
|
||||
--------------------------------------------------------------------------------
|
||||
http://www.ioplex.com/~miallen/encdec/ (binary pack/unpack utilities)
|
||||
|
||||
The Java API would take an object, and a list of field names, then use the
|
||||
Java Reflection API to read or write those fields during packing and
|
||||
unpacking.
|
||||
|
||||
I.e. if you are going to unpack a tpl with format string A(if), you
|
||||
might create a Java class that has two instance variables (an int and
|
||||
a double). Then you create an object of that class, and pass it to
|
||||
tpl_map (or perhaps a constructor for the Tpl class), like
|
||||
|
||||
class Unpacker {
|
||||
int count;
|
||||
double weight;
|
||||
}
|
||||
...
|
||||
Unpacker up = new Unpacker();
|
||||
Tpl tn = new Tpl("A(if)", up, "count", "weight");
|
||||
tn.tpl_unpack(1); // stores unpacked values into count,weight using Reflection
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Ruby API ideas
|
||||
--------------------------------------------------------------------------------
|
||||
#!/usr/local/ruby/bin/ruby -w
|
||||
|
||||
class Tpl < Hash
|
||||
def initialize(fmt, *args)
|
||||
@fmt = fmt
|
||||
@args = args
|
||||
end
|
||||
|
||||
def pack
|
||||
@args.each {|key| puts "#{key} #{self[key]}"}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
p = Tpl.new("A(i)", :id);
|
||||
10.times do |i|
|
||||
p[:id] = i
|
||||
p.pack
|
||||
end
|
||||
p.dump("/tmp/file.tpl") # p.dump(arg) checks arg.respond_to?(:write)
|
||||
|
||||
p = Tpl.new("A(i)", :id);
|
||||
p.load("/tmp/file.tpl")
|
||||
p.unpack(1) {|h| puts h[:id]}
|
302
doc/txt/perl.txt
Normal file
@ -0,0 +1,302 @@
|
||||
tpl Perl API
|
||||
============
|
||||
Troy D. Hanson <troydhanson@comcast.net>
|
||||
v1.1, April 2007
|
||||
|
||||
include::sflogo.txt[]
|
||||
include::topnav.txt[]
|
||||
|
||||
Perl API
|
||||
--------
|
||||
include::toc.txt[]
|
||||
|
||||
The Perl API for reading and writing tpl is nearly identical to the C API. This
|
||||
document will briefly explain the Perl API and provide examples. The chief
|
||||
motivation for having a Perl API is to communicate with C programs that use tpl.
|
||||
|
||||
[TIP]
|
||||
.Start with the C API
|
||||
This document assumes familiarity with the C API. The concepts of using tpl
|
||||
are not explained here. For an introduction to tpl and its C API, see the
|
||||
link:userguide.html[User Guide].
|
||||
|
||||
Tpl.pm
|
||||
~~~~~~
|
||||
The `Tpl.pm` file (in the `lang/perl`) directory contains the Perl module. You
|
||||
can copy it to another directory if you wish. Your Perl program may need to
|
||||
include a `use lib` statement to find the module.
|
||||
|
||||
#!/usr/bin/perl
|
||||
use lib "/some/directory";
|
||||
use Tpl;
|
||||
|
||||
tpl_map
|
||||
~~~~~~~
|
||||
This function resembles the C version, except that it's invoked via the `Tpl`
|
||||
module, and it takes references to Perl variables after the format string.
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
|
||||
The return value is a tpl object; all other API calls are object methods.
|
||||
Incidentally, there is no `tpl_free()` method corresponding to the C API.
|
||||
|
||||
Fixed-length arrays
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Format strings such as `i#` denote a fixed-length array. In the Perl API,
|
||||
fixed-length arrays require two arguments: a list reference, and the fixed
|
||||
length. For example:
|
||||
|
||||
my @x;
|
||||
my $tpl = Tpl->tpl_map("i#", \@x, 10);
|
||||
|
||||
When fixed-length arrays are packed or unpacked, the specified number of
|
||||
elements will be copied from (or placed into) the designated list.
|
||||
|
||||
Structures
|
||||
^^^^^^^^^^
|
||||
Format strings containing `S(...)` are handled in the Perl API as if only the
|
||||
interior, parenthesized part was present. (It does not work like the C API). So
|
||||
simply ignore the `S(...)` and consider only its interior format characters when
|
||||
constructing the argument list:
|
||||
|
||||
my ($str, $int);
|
||||
my $tpl = Tpl->tpl_map("S(si)", \$str, \$int);
|
||||
|
||||
It really only makes sense to use `S(...)` in a format string in the Perl API if
|
||||
you are communicating with a C program that uses structures.
|
||||
|
||||
tpl_pack
|
||||
~~~~~~~~
|
||||
This is nearly identical to the C version. The only argument is the index
|
||||
number to pack.
|
||||
|
||||
$tpl->tpl_pack(1);
|
||||
|
||||
tpl_dump
|
||||
~~~~~~~~
|
||||
This method is a little different than the C version. Given no arguments, it
|
||||
returns the tpl image; given one argument it writes a file with that name.
|
||||
|
||||
$tpl->tpl_dump("demo.tpl"); # writes demo.tpl
|
||||
|
||||
Or,
|
||||
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
The tpl image is a binary buffer. You can do whatever you want with it, such as
|
||||
write it to a socket or pipe (probably to C program listening on the other end),
|
||||
or save it somewhere and later re-load it using `tpl_load()`.
|
||||
|
||||
tpl_load
|
||||
~~~~~~~~
|
||||
This method loads a tpl image from a file or from a Perl variable. It takes
|
||||
one argument. If it's not a reference, it's assumed to be a filename to load.
|
||||
|
||||
$tpl->tpl_load("demo.tpl");
|
||||
|
||||
Otherwise, if the argument is a Perl reference, it's construed as a variable
|
||||
containing the tpl image:
|
||||
|
||||
$tpl->tpl_load(\$img);
|
||||
|
||||
The method will `die` if the image is invalid or the file doesn't exist. You
|
||||
can wrap it with `eval` to catch such errors:
|
||||
|
||||
eval { $tpl->tpl_load(\$img); };
|
||||
print "failed to load\n" if $@;
|
||||
|
||||
tpl_unpack
|
||||
~~~~~~~~~~
|
||||
This is nearly identical to the C version. The only argument is the index
|
||||
number to unpack.
|
||||
|
||||
$tpl->tpl_unpack(1);
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Integer array
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.Packing A(i) to file
|
||||
--------------------------------------------------------------------------------
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) {
|
||||
$tpl->tpl_pack(1);
|
||||
}
|
||||
$tpl->tpl_dump("demo.tpl");
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.Unpacking A(i) from file
|
||||
--------------------------------------------------------------------------------
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Tpl;
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(i)",\$j);
|
||||
$tpl2->tpl_load("demo.tpl");
|
||||
while($tpl2->tpl_unpack(1) > 0) {
|
||||
print "$j\n";
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Message-passing
|
||||
~~~~~~~~~~~~~~~
|
||||
While the bulk of this example is socket handling, it demonstrates how you can
|
||||
use tpl as a message-passing format. In the real-world, you might have a C
|
||||
server and a Perl client, for example. In this example, we'll code both a client
|
||||
and a server in Perl.
|
||||
|
||||
.A server that sums integers
|
||||
********************************************************************************
|
||||
Programming literature is rife with contrived examples so we will follow in that
|
||||
tradition. Our server will do no more than sum a list of integers. But in doing
|
||||
so it will demonstrate message passing adequately. Both its input (the integer
|
||||
array) and its output (an integer) are tpl images, passed over a TCP/IP socket.
|
||||
********************************************************************************
|
||||
|
||||
Server
|
||||
^^^^^^
|
||||
The server waits for a connection from a client. When it gets one, it accepts
|
||||
the connection and immediately forks a child process to handle it. Then it goes
|
||||
back to waiting for another new connection.
|
||||
|
||||
The server child process handles the client by loading and unpacking the tpl
|
||||
image sent by the client (containing an array of integers). It calculates their
|
||||
sum and constructs a new tpl image containing the sum, which it sends back to
|
||||
the client.
|
||||
|
||||
.Server
|
||||
--------------------------------------------------------------------------------
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use Tpl;
|
||||
|
||||
$SIG{CHLD} = "IGNORE"; # don't create zombies
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
sub handle_client {
|
||||
my $client = shift;
|
||||
|
||||
undef $/;
|
||||
my $request = <$client>; # get request (slurp)
|
||||
|
||||
# read input array, and calculate total
|
||||
my ($i,$total);
|
||||
my $tpl = Tpl->tpl_map("A(i)", \$i);
|
||||
eval { $tpl->tpl_load(\$request); };
|
||||
die "received invalid tpl" if $@;
|
||||
$total += $i while $tpl->tpl_unpack(1) > 0;
|
||||
|
||||
# formulate response and send
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
$tpl2->tpl_pack(0);
|
||||
my $response = $tpl2->tpl_dump();
|
||||
print $client $response;
|
||||
close $client;
|
||||
}
|
||||
|
||||
my $server = IO::Socket::INET->new(LocalPort => $port,
|
||||
Type => SOCK_STREAM,
|
||||
Reuse => 1,
|
||||
Listen => 10 )
|
||||
or die "Can't listen on port $port: $!\n";
|
||||
|
||||
while (1) {
|
||||
my $client = $server->accept();
|
||||
next unless $client;
|
||||
# new connection
|
||||
my $pid = fork;
|
||||
die "can't fork: $!\n" unless defined $pid;
|
||||
if ($pid > 0) {
|
||||
# parent
|
||||
close $client;
|
||||
} elsif ($pid == 0) {
|
||||
# child
|
||||
handle_client($client);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
close ($server);
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Client
|
||||
^^^^^^
|
||||
|
||||
The client is a simpler program. It constructs the tpl image containing the
|
||||
integer array (taken from its command-line arguments), connects to the server
|
||||
and sends the tpl image to it, and then awaits the response tpl. The response
|
||||
containing the sum is loaded, unpacked and printed.
|
||||
|
||||
.Client
|
||||
--------------------------------------------------------------------------------
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use Tpl;
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
# construct tpl
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
$tpl->tpl_pack(1) while ($i=shift @ARGV);
|
||||
my $request = $tpl->tpl_dump();
|
||||
|
||||
# send to server, get response
|
||||
my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect";
|
||||
print $socket $request;
|
||||
shutdown($socket,1); # done writing (half-close)
|
||||
undef $/;
|
||||
my $response = <$socket>; # get reply (slurp)
|
||||
|
||||
# decode response (or print error)
|
||||
my $total;
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
eval { $tpl2->tpl_load(\$response); };
|
||||
die "invalid response\n" if $@;
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "total is $total\n";
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Running thise example
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
If the client and server programs are in `client.pl` and `server.pl`, then
|
||||
you can run the example by starting the server in one window:
|
||||
|
||||
./server.pl
|
||||
|
||||
Then run the client in another window. E.g.,
|
||||
|
||||
./client.pl 1 2 3 4 5
|
||||
|
||||
The client runs and then exits, printing:
|
||||
|
||||
total is 15
|
||||
|
||||
You can re-run the client with different arguments. When done, type `Ctrl-C` in
|
||||
the server window to terminate it.
|
||||
|
||||
// vim: set tw=80 wm=2 syntax=asciidoc:
|
||||
|
5
doc/txt/sflogo.txt
Normal file
@ -0,0 +1,5 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<a style="float: right;" href="http://sourceforge.net/projects/tpl"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=157637&type=16" width="150" height="40" alt="SourceForge.net" /></a>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
85
doc/txt/toc.txt
Normal file
@ -0,0 +1,85 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<div id="toc"></div>
|
||||
<script>
|
||||
window.onload=generate_TOC
|
||||
|
||||
/* Author: Mihai Bazon, September 2002
|
||||
* http://students.infoiasi.ro/~mishoo
|
||||
*
|
||||
* Table Of Content generator
|
||||
* Version: 0.4
|
||||
*
|
||||
* Feel free to use this script under the terms of the GNU General Public
|
||||
* License, as long as you do not remove or alter this notice.
|
||||
*/
|
||||
|
||||
/* modified by Troy D. Hanson, September 2006. License: GPL */
|
||||
|
||||
function H_getText(el) {
|
||||
var text = "";
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 3 /* Node.TEXT_NODE, IE doesn't speak constants */)
|
||||
text += i.data;
|
||||
else if (i.firstChild != null)
|
||||
text += H_getText(i);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function TOC_EL(el, text, level) {
|
||||
this.element = el;
|
||||
this.text = text;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
function getHeadlines(el) {
|
||||
var l = new Array;
|
||||
var rx = /[hH]([2-3])/;
|
||||
// internal recursive function that scans the DOM tree
|
||||
var rec = function (el) {
|
||||
for (var i = el.firstChild; i != null; i = i.nextSibling) {
|
||||
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
|
||||
if (rx.exec(i.tagName))
|
||||
l[l.length] = new TOC_EL(i, H_getText(i), parseInt(RegExp.$1));
|
||||
rec(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
rec(el);
|
||||
return l;
|
||||
}
|
||||
|
||||
function generate_TOC() {
|
||||
var parent = document.getElementById("toc");
|
||||
var toc_hdr = document.createElement("div");
|
||||
var toc_hdr_txt = document.createTextNode("CONTENTS");
|
||||
toc_hdr.appendChild(toc_hdr_txt);
|
||||
/* toc_hdr.setAttribute("id","hdr"); */
|
||||
toc_hdr.id = "hdr";
|
||||
parent.appendChild(toc_hdr);
|
||||
var hs = getHeadlines(document.getElementsByTagName("body")[0]);
|
||||
for (var i = 0; i < hs.length; ++i) {
|
||||
var hi = hs[i];
|
||||
var d = document.createElement("div");
|
||||
if (hi.element.id == "") hi.element.id = "gen" + i;
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + hi.element.id;
|
||||
a.appendChild(document.createTextNode(hi.text));
|
||||
d.appendChild(a);
|
||||
d.className = "level" + hi.level;
|
||||
parent.appendChild(d);
|
||||
/*
|
||||
if (hi.level == 3) {
|
||||
var dvtop = document.createElement("div");
|
||||
dvtop.className = "toplink";
|
||||
dvtop.appendChild(document.createTextNode("^top^"));
|
||||
dvtop.onclick=function(){scrollTo(0,0);};
|
||||
hi.element.appendChild(dvtop);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
10
doc/txt/topnav.txt
Normal file
@ -0,0 +1,10 @@
|
||||
ifdef::backend-xhtml11[]
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
<div id="topnav" style="font-size: 9pt; font-family: sans-serif;">
|
||||
<a style="padding: 8px;" href="http://sourceforge.net/projects/tpl/">sf.net summary page</a> >
|
||||
<a style="padding: 8px;" href="index.html">tpl home</a> >
|
||||
{doctitle}
|
||||
<a style="padding: 8px;" href="userguide.pdf">[View PDF]</a>
|
||||
</div>
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
endif::backend-xhtml11[]
|
1264
doc/txt/userguide.txt
Normal file
475
lang/perl/Tpl.pm
Normal file
@ -0,0 +1,475 @@
|
||||
package Tpl;
|
||||
|
||||
# Copyright (c) 2005-2007, Troy Hanson http://tpl.sourceforge.net
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Config; # to get the size of "double" on this platform
|
||||
|
||||
use bytes; # always use byte (not unicode char) offsets w/tpl images
|
||||
|
||||
our $VERSION = 1.1;
|
||||
|
||||
# tpl object is a reference to a hash with these keys:
|
||||
#
|
||||
# A(0):
|
||||
# ... :
|
||||
# A(n):
|
||||
#
|
||||
# where each A(i) refers to an A node, except A(0) is the root node.
|
||||
#
|
||||
# For each hash key (A node or root node), the value of that key is
|
||||
# a list reference. The members are of the list are the node's children.
|
||||
# They're represented as "Ai" (for A nodes) where i is a positive integer;
|
||||
# for non-A nodes the representation is [type,addr] e.g. [ "i", \$some_integer]
|
||||
#
|
||||
# For example,
|
||||
# Tpl->map("iA(ib)", \$x, \$y, \$z);
|
||||
# returns a tpl object which is a reference to a hash with these keys/values:
|
||||
#
|
||||
# $self->{A0} = [ [ "i", \$x ], "A1" ];
|
||||
# $self->{A1} = [ [ "i", \$y ], [ "b", \$z ] ];
|
||||
#
|
||||
# Now if A1 (that is, the "A(ib)" node) is packed, the tpl object acquires
|
||||
# another hash key/value:
|
||||
# $self->{P1} = [ $binary_int, $binary_byte ];
|
||||
# and repeated calls to pack A1 append further $binary elements.
|
||||
#
|
||||
sub tpl_map {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $fmt = shift;
|
||||
my @astack = (0); # stack of current A node's lineage in tpl tree
|
||||
my $a_count=0; # running count of A's, thus an index of them
|
||||
my $self = {}; # populate below
|
||||
my ($lparen_level,$expect_lparen,$in_structure)=(0,0,0);
|
||||
for (my $i=0; $i < length $fmt; $i++) {
|
||||
my $c = substr($fmt,$i,1);
|
||||
if ($c eq 'A') {
|
||||
$a_count++;
|
||||
push @{ $self->{"A" . $astack[-1]} }, "A$a_count";
|
||||
push @astack, $a_count;
|
||||
$expect_lparen=1;
|
||||
} elsif ($c eq '(') {
|
||||
die "invalid format $fmt" unless $expect_lparen;
|
||||
$expect_lparen=0;
|
||||
$lparen_level++;
|
||||
} elsif ($c eq ')') {
|
||||
$lparen_level--;
|
||||
die "invalid format $fmt" if $lparen_level < 0;
|
||||
die "invalid format $fmt" if substr($fmt,$i-1,1) eq '(';
|
||||
if ($in_structure && ($in_structure-1 == $lparen_level)) {
|
||||
$in_structure=0;
|
||||
} else {
|
||||
pop @astack; # rparen ends A() type, not S() type
|
||||
}
|
||||
} elsif ($c eq 'S') {
|
||||
# in perl we just parse and ignore the S() construct
|
||||
$expect_lparen=1;
|
||||
$in_structure=1+$lparen_level; # so we can tell where S fmt ends
|
||||
} elsif ($c =~ /^(i|u|B|s|c|f|I|U)$/) {
|
||||
die "invalid format $fmt" if $expect_lparen;
|
||||
my $r = shift;
|
||||
die "no reference for $c (position $i of $fmt)" unless ref($r);
|
||||
if (($c eq "f") and ($Config{doublesize} != 8)) {
|
||||
die "double not 8 bytes on this platform";
|
||||
}
|
||||
if (($c =~ /(U|I)/) and not defined ($Config{use64bitint})) {
|
||||
die "Tpl.pm: this 32-bit Perl can't pack/unpack 64-bit I/U integers\n";
|
||||
}
|
||||
push @{ $self->{"A" . $astack[-1]} }, [ $c , $r ];
|
||||
} elsif ($c eq "#") {
|
||||
# test for previous iucfIU
|
||||
die "unallowed length modifer" unless $self->{"A" . $astack[-1]}->[-1]->[0] =~ /^(i|u|c|I|U|f)$/;
|
||||
my $n = shift;
|
||||
die "non-numeric # length modifer" unless $n =~ /^\d+$/;
|
||||
push @{ $self->{"A" . $astack[-1]}->[-1] }, $n;
|
||||
push @{ $self->{"#"}}, $n; # master array of octothorpe lengths
|
||||
} else {
|
||||
die "invalid character $c in format $fmt";
|
||||
}
|
||||
}
|
||||
die "invalid format $fmt" if $lparen_level != 0;
|
||||
$self->{fmt} = $fmt;
|
||||
bless $self;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub tpl_format {
|
||||
my $self = shift;
|
||||
return $self->{fmt};
|
||||
}
|
||||
|
||||
sub tpl_pack {
|
||||
my $self = shift;
|
||||
my $i = shift;
|
||||
die "invalid index" unless defined $self->{"A$i"};
|
||||
die "tpl for unpacking only" if defined $self->{"loaded"};
|
||||
$self->{"packed"}++;
|
||||
$self->{"P$i"} = undef if $i == 0; # node 0 doesn't accumulate
|
||||
my @bb;
|
||||
foreach my $node (@{ $self->{"A$i"} }) {
|
||||
if (ref($node)) {
|
||||
my ($type,$addr,$fxlen) = @{ $node };
|
||||
if (defined $fxlen) { # octothorpic array
|
||||
push @bb, CORE::pack("l$fxlen",@$addr) if $type eq "i"; # int
|
||||
push @bb, CORE::pack("L$fxlen",@$addr) if $type eq "u"; # uint
|
||||
push @bb, CORE::pack("C$fxlen",@$addr) if $type eq "c"; # byte
|
||||
push @bb, CORE::pack("d$fxlen",@$addr) if $type eq "f"; # double
|
||||
push @bb, CORE::pack("q$fxlen",@$addr) if $type eq "I"; # int64
|
||||
push @bb, CORE::pack("Q$fxlen",@$addr) if $type eq "U"; # uint64
|
||||
} else {
|
||||
# non-octothorpic singleton
|
||||
push @bb, CORE::pack("l",$$addr) if $type eq "i"; # int
|
||||
push @bb, CORE::pack("L",$$addr) if $type eq "u"; # uint
|
||||
push @bb, CORE::pack("C",$$addr) if $type eq "c"; # byte
|
||||
push @bb, CORE::pack("d",$$addr) if $type eq "f"; # double (8 byte)
|
||||
push @bb, CORE::pack("q",$$addr) if $type eq "I"; # int64
|
||||
push @bb, CORE::pack("Q",$$addr) if $type eq "U"; # uint64
|
||||
if ($type =~ /^(B|s)$/) { # string/binary
|
||||
push @bb, CORE::pack("L", length($$addr));
|
||||
push @bb, CORE::pack("a*", $$addr);
|
||||
}
|
||||
}
|
||||
} elsif ($node =~ /^A(\d+)$/) {
|
||||
# encode array length (int) and the array data into one scalar
|
||||
my $alen = pack("l", scalar @{ $self->{"P$1"} or [] });
|
||||
my $abod = (join "", @{ $self->{"P$1"} or [] });
|
||||
push @bb, $alen . $abod;
|
||||
$self->{"P$1"} = undef;
|
||||
} else {
|
||||
die "internal error; invalid node symbol $node";
|
||||
}
|
||||
}
|
||||
push @{ $self->{"P$i"} }, (join "", @bb);
|
||||
}
|
||||
|
||||
sub big_endian {
|
||||
return (CORE::unpack("C", CORE::pack("L",1)) == 1) ? 0 : 1;
|
||||
}
|
||||
|
||||
sub tpl_dump {
|
||||
my $self = shift;
|
||||
my $filename = shift;
|
||||
|
||||
$self->tpl_pack(0) if not defined $self->{"P0"};
|
||||
my $format = $self->tpl_format;
|
||||
my $octothorpe_lens = CORE::pack("L*", @{ $self->{"#"} or [] });
|
||||
my $data = (join "", @{ $self->{"P0"} });
|
||||
my $ov_len = length($format) + 1 + length($octothorpe_lens) + length($data) + 8;
|
||||
my $flags = big_endian() ? 1 : 0;
|
||||
my $preamble = CORE::pack("CLZ*", $flags, $ov_len, $format);
|
||||
my $tpl = "tpl" . $preamble . $octothorpe_lens . $data;
|
||||
return $tpl unless $filename;
|
||||
|
||||
# here for file output
|
||||
open TPL, ">$filename" or die "can't open $filename: $!";
|
||||
print TPL $tpl;
|
||||
close TPL;
|
||||
}
|
||||
|
||||
sub tpl_peek {
|
||||
my $invocant = shift;
|
||||
my $class = ref($invocant) || $invocant;
|
||||
my $tplhandle = shift;
|
||||
my $tpl;
|
||||
|
||||
if (ref($tplhandle)) {
|
||||
$tpl = $$tplhandle;
|
||||
} else {
|
||||
open TPL, "<$tplhandle" or die "can't open $tplhandle: $!";
|
||||
undef $/; # slurp
|
||||
$tpl = <TPL>;
|
||||
close TPL;
|
||||
}
|
||||
die "invalid tpl file" unless ($tpl =~ /^tpl/);
|
||||
return (unpack("Z*", substr($tpl,8)));
|
||||
}
|
||||
|
||||
sub tpl_load {
|
||||
my $self = shift;
|
||||
my $tplhandle = shift;
|
||||
|
||||
die "tpl for packing only" if $self->{"packed"};
|
||||
die "tpl reloading not supported" if $self->{"loaded"};
|
||||
|
||||
# read tpl image from file or was it passed directly via ref?
|
||||
my $tpl;
|
||||
if (ref($tplhandle)) {
|
||||
$tpl = $$tplhandle;
|
||||
} else {
|
||||
open TPL, "<$tplhandle" or die "can't open $tplhandle: $!";
|
||||
undef $/; # slurp
|
||||
$tpl = <TPL>;
|
||||
close TPL;
|
||||
}
|
||||
|
||||
$self->{"TI"} = $tpl;
|
||||
$self->{"TL"} = length $tpl;
|
||||
# verify preamble
|
||||
die "invalid image -1" unless length($tpl) >= 9;
|
||||
die "invalid image -2" unless $tpl =~ /^tpl/;
|
||||
my $flags = CORE::unpack("C", substr($tpl,3,1));
|
||||
$self->{"xendian"} = 1 if (big_endian() != ($flags & 1));
|
||||
$self->{"UF"} = ($flags & 1) ? "N" : "V";
|
||||
my $ov_len = CORE::unpack($self->{"UF"}, substr($tpl,4,4));
|
||||
die "invalid image -3" unless $ov_len == length($tpl);
|
||||
my $format = CORE::unpack("Z*", substr($tpl,8));
|
||||
die "format mismatch" unless $format eq $self->tpl_format();
|
||||
my @octothorpe_lens = @{ $self->{"#"} or [] };
|
||||
my $ol = 8 + length($format) + 1; # start of octothorpe lengths
|
||||
for (my $i=0; $i < (scalar @octothorpe_lens); $i++) {
|
||||
my $len = CORE::unpack($self->{"UF"}, substr($tpl,$ol,4));
|
||||
my $olen = $octothorpe_lens[$i];
|
||||
die "fixed-length array size mismatch" unless $olen == $len;
|
||||
$ol += 4;
|
||||
}
|
||||
my $dv = $ol; # start of packed data
|
||||
my $len = $self->serlen("A0",$dv);
|
||||
die "invalid image -4" if $len == -1;
|
||||
die "invalid image -5" if (length($tpl) != $len + $dv);
|
||||
$self->{"C0"} = $dv;
|
||||
$self->{"loaded"} = 1;
|
||||
$self->unpackA0; # prepare root child nodes for use
|
||||
}
|
||||
|
||||
# byte reverse a word (any length)
|
||||
sub reversi {
|
||||
my $word = shift;
|
||||
my @w = split //, $word;
|
||||
my $r = join "", (reverse @w);
|
||||
return $r;
|
||||
}
|
||||
|
||||
#
|
||||
# while unpacking, the object has these keys in its hash:
|
||||
# C0
|
||||
# C1
|
||||
# ...
|
||||
# C<n>
|
||||
# These are indices (into the tpl image $self->{"TI"}) from which node n
|
||||
# is being unpacked. I.e. as array elements of node n are unpacked, C<n>
|
||||
# advances through the tpl image.
|
||||
#
|
||||
# Similarly, elements
|
||||
# N1
|
||||
# N2
|
||||
# ...
|
||||
# N<n>
|
||||
# refer to the remaining array count for node n.
|
||||
#
|
||||
sub tpl_unpack {
|
||||
my $self = shift;
|
||||
my $n = shift;
|
||||
my $ax = "A$n";
|
||||
my $cx = "C$n";
|
||||
my $nx = "N$n";
|
||||
my $rc;
|
||||
|
||||
die "tpl for packing only" if $self->{"packed"};
|
||||
die "tpl not loaded" unless $self->{"loaded"};
|
||||
|
||||
# decrement count for non root array nodes
|
||||
if ($n > 0) {
|
||||
return 0 if $self->{$nx} <= 0;
|
||||
$rc = $self->{$nx}--;
|
||||
}
|
||||
|
||||
for my $c (@{ $self->{$ax} }) {
|
||||
if (ref($c)) {
|
||||
my ($type,$addr,$fxlen) = @$c;
|
||||
if (defined $fxlen) { # octothorpic unpack
|
||||
@{ $addr } = (); # empty existing list before pushing elements
|
||||
for(my $i=0; $i < $fxlen; $i++) {
|
||||
if ($type eq "u") { # uint
|
||||
push @{ $addr }, CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$self->{$cx},4));
|
||||
$self->{$cx} += 4;
|
||||
} elsif ($type eq "i") { #int (see note below re:signed int)
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},4);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
push @{ $addr }, CORE::unpack("l", $intbytes);
|
||||
$self->{$cx} += 4;
|
||||
} elsif ($type eq "c") { # byte
|
||||
push @{ $addr }, CORE::unpack("C",
|
||||
substr($self->{"TI"},$self->{$cx},1));
|
||||
$self->{$cx} += 1;
|
||||
} elsif ($type eq "f") { # double
|
||||
my $double_bytes = substr($self->{"TI"},$self->{$cx},8);
|
||||
$double_bytes = reversi($double_bytes) if $self->{"xendian"};
|
||||
push @{ $addr }, CORE::unpack("d", $double_bytes );
|
||||
$self->{$cx} += 8;
|
||||
} elsif ($type eq "I") { #int64
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},8);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
push @{ $addr }, CORE::unpack("q", $intbytes);
|
||||
$self->{$cx} += 8;
|
||||
} elsif ($type eq "U") { #uint64
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},8);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
push @{ $addr }, CORE::unpack("Q", $intbytes);
|
||||
$self->{$cx} += 8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# non-octothorpe (singleton)
|
||||
if ($type eq "u") { # uint
|
||||
${$addr} = CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$self->{$cx},4));
|
||||
$self->{$cx} += 4;
|
||||
} elsif ($type eq "i") { # int
|
||||
# while perl's N or V conversions unpack an unsigned
|
||||
# long from either big or little endian format
|
||||
# respectively, when it comes to *signed* int, perl
|
||||
# only has 'l' (which assumes native endianness).
|
||||
# So we have to manually reverse the bytes in a
|
||||
# cross-endian 'int' unpacking scenario.
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},4);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
${$addr} = CORE::unpack("l", $intbytes);
|
||||
$self->{$cx} += 4;
|
||||
} elsif ($type eq 'c') { # byte
|
||||
${$c->[1]} = CORE::unpack("C",
|
||||
substr($self->{"TI"},$self->{$cx},1));
|
||||
$self->{$cx} += 1;
|
||||
} elsif ($type eq 'f') { # double
|
||||
${$addr} = CORE::unpack("d",
|
||||
substr($self->{"TI"},$self->{$cx},8));
|
||||
$self->{$cx} += 8;
|
||||
} elsif ($type =~ /^(B|s)$/) { # string/binary
|
||||
my $slen = CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$self->{$cx},4));
|
||||
$self->{$cx} += 4;
|
||||
${$addr} = CORE::unpack("a$slen",
|
||||
substr($self->{"TI"},$self->{$cx},$slen));
|
||||
$self->{$cx} += $slen;
|
||||
} elsif ($type eq "I") { # int64
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},8);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
${$addr} = CORE::unpack("q", $intbytes);
|
||||
$self->{$cx} += 8;
|
||||
} elsif ($type eq "U") { # uint64
|
||||
my $intbytes = substr($self->{"TI"},$self->{$cx},8);
|
||||
$intbytes = reversi($intbytes) if $self->{"xendian"};
|
||||
${$addr} = CORE::unpack("Q", $intbytes);
|
||||
$self->{$cx} += 8;
|
||||
} else { die "internal error"; }
|
||||
}
|
||||
} elsif ($c =~ /^A(\d+)$/) {
|
||||
my $alen = $self->serlen($c,$self->{$cx});
|
||||
$self->{"N$1"} = CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$self->{$cx},4)); # get array count
|
||||
$self->{"C$1"} = $self->{$cx} + 4; # set array node's data start
|
||||
$self->{$cx} += $alen; # step over array node's data
|
||||
} else { die "internal error"; }
|
||||
}
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
# specialized function to prepare root's child A nodes for initial use
|
||||
sub unpackA0 {
|
||||
my $self = shift;
|
||||
my $ax = "A0";
|
||||
my $cx = "C0";
|
||||
my $c0 = $self->{$cx};
|
||||
|
||||
for my $c (@{ $self->{$ax} }) {
|
||||
next if ref($c); # skip non-A nodes
|
||||
if ($c =~ /^A(\d+)$/) {
|
||||
my $alen = $self->serlen($c,$c0);
|
||||
$self->{"N$1"} = CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$c0,4)); # get array count
|
||||
$self->{"C$1"} = $c0 + 4; # set array node's data start
|
||||
$c0 += $alen; # step over array node's data
|
||||
} else { die "internal error"; }
|
||||
}
|
||||
}
|
||||
|
||||
# ascertain serialized length of given node by walking
|
||||
sub serlen {
|
||||
my $self = shift;
|
||||
my $ax = shift;
|
||||
my $dv = shift;
|
||||
|
||||
my $len = 0;
|
||||
|
||||
my $num;
|
||||
if ($ax eq "A0") {
|
||||
$num = 1;
|
||||
} else {
|
||||
return -1 unless $self->{"TL"} >= $dv + 4;
|
||||
$num = CORE::unpack($self->{"UF"},substr($self->{"TI"},$dv,4));
|
||||
$dv += 4;
|
||||
$len += 4;
|
||||
}
|
||||
|
||||
while ($num-- > 0) {
|
||||
for my $c (@{ $self->{$ax} }) {
|
||||
if (ref($c)) {
|
||||
my $n = 1;
|
||||
$n = $c->[2] if (@$c > 2); # octothorpic array length
|
||||
if ($c->[0] =~ /^(i|u)$/) { # int/uint
|
||||
return -1 unless $self->{"TL"} >= $dv + 4*$n;
|
||||
$len += 4*$n;
|
||||
$dv += 4*$n;
|
||||
} elsif ($c->[0] eq "c") { # byte
|
||||
return -1 unless $self->{"TL"} >= $dv + 1*$n;
|
||||
$len += 1*$n;
|
||||
$dv += 1*$n;
|
||||
} elsif ($c->[0] eq "f") { # double
|
||||
return -1 unless $self->{"TL"} >= $dv + 8*$n;
|
||||
$len += 8*$n;
|
||||
$dv += 8*$n;
|
||||
} elsif ($c->[0] =~ /(I|U)/) { # int64/uint64
|
||||
return -1 unless $self->{"TL"} >= $dv + 8*$n;
|
||||
$len += 8*$n;
|
||||
$dv += 8*$n;
|
||||
} elsif ($c->[0] =~ /^(B|s)$/) { # string/binary
|
||||
return -1 unless $self->{"TL"} >= $dv + 4;
|
||||
my $slen = CORE::unpack($self->{"UF"},
|
||||
substr($self->{"TI"},$dv,4));
|
||||
$len += 4;
|
||||
$dv += 4;
|
||||
return -1 unless $self->{"TL"} >= $dv + $slen;
|
||||
$len += $slen;
|
||||
$dv += $slen;
|
||||
} else { die "internal error" }
|
||||
} elsif ($c =~ /^A/) {
|
||||
my $alen = $self->serlen($c,$dv);
|
||||
return -1 if $alen == -1;
|
||||
$dv += $alen;
|
||||
$len += $alen;
|
||||
} else { die "internal error"; }
|
||||
}
|
||||
}
|
||||
return $len;
|
||||
}
|
||||
|
||||
1
|
9
lang/perl/tests/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all: run_tests
|
||||
|
||||
run_tests:
|
||||
perl ./do_tests
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f test*.out
|
29
lang/perl/tests/README
Normal file
@ -0,0 +1,29 @@
|
||||
Run 'make' to run the tests.
|
||||
|
||||
Run 'make clean' to clean up the temporary files.
|
||||
|
||||
Description of tests
|
||||
=============================================================================
|
||||
test1 pack A(i) to file, unpack
|
||||
test2 pack A(i) to memory, unpack
|
||||
test3 pack A(i) to memory, pipe through tplxml (to make XML)
|
||||
test4 pack A(i) to file, convert to XML, convert back to tpl (using tplxml)
|
||||
test5 pack A(b) to file, unpack
|
||||
test6 pack A(b) to memory, pipe through tplxml (to make XML)
|
||||
test7 pack A(b) to file, convert to XML, convert back to tpl (using tplxml)
|
||||
test8 pack A(s) (has embedded &, < and > in strings to test quoting in XML)
|
||||
test9 pack A(u) to file, unpack
|
||||
test10 pack A(u) to memory, convert via tplxml
|
||||
test11 pack format B using a four-byte binary buffer, unpack and print
|
||||
test12 pack A(d) to file, unpack
|
||||
test13 pack A(d) to memory, convert via tplxml
|
||||
test14 unpack big-endian i (-2) (on little-endian machine, tests reversi)
|
||||
test15 unpack little-endian i (-3) (on big-endian machine, tests reversi)
|
||||
test16 pack to mem format B using a four-byte binary buffer, unpack and print
|
||||
test17 pack and unpack S(ic)
|
||||
test18 pack and unpack i#
|
||||
test19 pack and unpack i#i#
|
||||
test20 pack A(S(ci#)) to file, convert to XML, then back to tpl (cf test81.c)
|
||||
test21 Tpl->tpl_peek in-memory image
|
||||
test22 Tpl->tpl_peek file image
|
||||
test23 test I/U (only succeeds on 64-bit perl)
|
31
lang/perl/tests/client.pl
Executable file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
# construct tpl
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
$tpl->tpl_pack(1) while ($i=shift @ARGV);
|
||||
my $request = $tpl->tpl_dump();
|
||||
|
||||
# send to server, get response
|
||||
my $socket = IO::Socket::INET->new("localhost:$port") or die "can't connect";
|
||||
print $socket $request;
|
||||
shutdown($socket,1); # done writing (half-close)
|
||||
undef $/;
|
||||
my $response = <$socket>; # get reply (slurp)
|
||||
|
||||
# decode response (or print error)
|
||||
my $total;
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
eval { $tpl2->tpl_load(\$response); };
|
||||
die "invalid response\n" if $@;
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "total is $total\n";
|
20
lang/perl/tests/do_tests
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my @tests;
|
||||
for (glob "test*[0-9]") {
|
||||
push @tests, $_ if -e "$_.ans";
|
||||
}
|
||||
|
||||
my $num_failed=0;
|
||||
|
||||
for my $test (@tests) {
|
||||
`./$test > $test.out`;
|
||||
`diff $test.out $test.ans`;
|
||||
print "$test failed\n" if $?;
|
||||
$num_failed++ if $?;
|
||||
}
|
||||
|
||||
print scalar @tests . " tests conducted, $num_failed failed.\n";
|
56
lang/perl/tests/server.pl
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
$SIG{CHLD} = "IGNORE"; # don't create zombies
|
||||
|
||||
our $port = 2000;
|
||||
|
||||
sub handle_client {
|
||||
my $client = shift;
|
||||
|
||||
undef $/;
|
||||
my $request = <$client>; # get request (slurp)
|
||||
|
||||
# read input array, and calculate total
|
||||
my ($i,$total);
|
||||
my $tpl = Tpl->tpl_map("A(i)", \$i);
|
||||
eval { $tpl->tpl_load(\$request); };
|
||||
die "received invalid tpl" if $@;
|
||||
$total += $i while $tpl->tpl_unpack(1) > 0;
|
||||
|
||||
# formulate response and send
|
||||
my $tpl2 = Tpl->tpl_map("i", \$total);
|
||||
$tpl2->tpl_pack(0);
|
||||
my $response = $tpl2->tpl_dump();
|
||||
print $client $response;
|
||||
close $client;
|
||||
}
|
||||
|
||||
my $server = IO::Socket::INET->new(LocalPort => $port,
|
||||
Type => SOCK_STREAM,
|
||||
Reuse => 1,
|
||||
Listen => 10 )
|
||||
or die "Can't listen on port $port: $!\n";
|
||||
|
||||
while (1) {
|
||||
my $client = $server->accept();
|
||||
next unless $client;
|
||||
# new connection
|
||||
my $pid = fork;
|
||||
die "can't fork: $!\n" unless defined $pid;
|
||||
if ($pid > 0) {
|
||||
#p arent
|
||||
close $client;
|
||||
} elsif ($pid == 0) {
|
||||
# child
|
||||
handle_client($client);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
close ($server);
|
23
lang/perl/tests/test1
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(i)",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
while($tpl2->tpl_unpack(1) > 0) { print "$j\n" }
|
||||
|
10
lang/perl/tests/test1.ans
Normal file
@ -0,0 +1,10 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
16
lang/perl/tests/test10
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(u)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
open TPLXML, "|../tplxml" or die "can't open tplxml: $!";
|
||||
print TPLXML $img;
|
||||
close TPLXML;
|
53
lang/perl/tests/test10.ans
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>
|
||||
<tplxml format="A(u)" fxlens="">
|
||||
<A>
|
||||
<el>
|
||||
<u>0</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>1</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>2</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>3</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>4</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>5</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>6</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>7</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>8</u>
|
||||
</el>
|
||||
<el>
|
||||
<u>9</u>
|
||||
</el>
|
||||
</A>
|
||||
</tplxml>
|
24
lang/perl/tests/test11
Executable file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("B",\$i);
|
||||
$i = pack("CCCC", 0xA, 0xB, 0xC, 0xD);
|
||||
$tpl->tpl_pack(0);
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
|
||||
$tpl = Tpl->tpl_map("B",\$i);
|
||||
$tpl->tpl_load($tmp1);
|
||||
$tpl->tpl_unpack(0);
|
||||
print "$i\n";
|
2
lang/perl/tests/test11.ans
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
23
lang/perl/tests/test12
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(f)",\$i);
|
||||
for($i=0; $i<10.0; $i+=2/3.0) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(f)",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
while($tpl2->tpl_unpack(1) > 0) { printf("%.6f\n", $j); }
|
||||
|
16
lang/perl/tests/test12.ans
Normal file
@ -0,0 +1,16 @@
|
||||
0.000000
|
||||
0.666667
|
||||
1.333333
|
||||
2.000000
|
||||
2.666667
|
||||
3.333333
|
||||
4.000000
|
||||
4.666667
|
||||
5.333333
|
||||
6.000000
|
||||
6.666667
|
||||
7.333333
|
||||
8.000000
|
||||
8.666667
|
||||
9.333333
|
||||
10.000000
|
16
lang/perl/tests/test13
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(f)",\$i);
|
||||
for($i=0; $i<10.0; $i+=2/3.0) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
open TPLXML, "|../tplxml" or die "can't open tplxml: $!";
|
||||
print TPLXML $img;
|
||||
close TPLXML;
|
71
lang/perl/tests/test13.ans
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>
|
||||
<tplxml format="A(f)" fxlens="">
|
||||
<A>
|
||||
<el>
|
||||
<f>0</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>0.666666666666667</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>1.33333333333333</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>2</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>2.66666666666667</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>3.33333333333333</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>4</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>4.66666666666667</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>5.33333333333333</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>6</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>6.66666666666667</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>7.33333333333333</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>8</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>8.66666666666667</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>9.33333333333333</f>
|
||||
</el>
|
||||
<el>
|
||||
<f>10</f>
|
||||
</el>
|
||||
</A>
|
||||
</tplxml>
|
17
lang/perl/tests/test14
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $tmp1 = "test14.tpl";
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("i",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "$j\n";
|
||||
|
||||
|
1
lang/perl/tests/test14.ans
Normal file
@ -0,0 +1 @@
|
||||
-2
|
BIN
lang/perl/tests/test14.tpl
Normal file
17
lang/perl/tests/test15
Executable file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $tmp1 = "test15.tpl";
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("i",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "$j\n";
|
||||
|
||||
|
1
lang/perl/tests/test15.ans
Normal file
@ -0,0 +1 @@
|
||||
-3
|
BIN
lang/perl/tests/test15.tpl
Normal file
22
lang/perl/tests/test16
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("B",\$i);
|
||||
$i = pack("CCCC", 0xA, 0xB, 0xC, 0xD);
|
||||
$tpl->tpl_pack(0);
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
|
||||
$tpl = Tpl->tpl_map("B",\$i);
|
||||
$tpl->tpl_load(\$img);
|
||||
$tpl->tpl_unpack(0);
|
||||
print "$i\n";
|
2
lang/perl/tests/test16.ans
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
25
lang/perl/tests/test17
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my ($i,$j)=(1,ord('a'));
|
||||
my $tpl = Tpl->tpl_map("S(ic)",\$i, \$j);
|
||||
$tpl->tpl_pack(0);
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
($i,$j)=(-9,"x");
|
||||
my $tpl2 = Tpl->tpl_map("S(ic)",\$i,\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
$tpl2->tpl_unpack(0);
|
||||
$j = chr($j);
|
||||
print "$i,$j\n";
|
||||
|
1
lang/perl/tests/test17.ans
Normal file
@ -0,0 +1 @@
|
||||
1,a
|
23
lang/perl/tests/test18
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my @i=(1,2,3,4);
|
||||
my $tpl = Tpl->tpl_map("i#",\@i, 3);
|
||||
$tpl->tpl_pack(0);
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my @j;
|
||||
my $tpl2 = Tpl->tpl_map("i#",\@j,3);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "$_\n" for @j;
|
3
lang/perl/tests/test18.ans
Normal file
@ -0,0 +1,3 @@
|
||||
1
|
||||
2
|
||||
3
|
25
lang/perl/tests/test19
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my @i=(1,2,3,4);
|
||||
my @j=(-1,-2,-3, -4);
|
||||
my $tpl = Tpl->tpl_map("i#i#",\@i, 3, \@j, 4);
|
||||
$tpl->tpl_pack(0);
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my (@x,@y);
|
||||
my $tpl2 = Tpl->tpl_map("i#i#",\@x, 3, \@y, 4);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "$_\n" for @x;
|
||||
print "$_\n" for @y;
|
7
lang/perl/tests/test19.ans
Normal file
@ -0,0 +1,7 @@
|
||||
1
|
||||
2
|
||||
3
|
||||
-1
|
||||
-2
|
||||
-3
|
||||
-4
|
18
lang/perl/tests/test2
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(i)",\$j);
|
||||
$tpl2->tpl_load(\$img);
|
||||
while($tpl2->tpl_unpack(1) > 0) { print "$j\n" }
|
||||
|
10
lang/perl/tests/test2.ans
Normal file
@ -0,0 +1,10 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
36
lang/perl/tests/test20
Executable file
@ -0,0 +1,36 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
my $tmp2 = "$pwd/$0_2.out";
|
||||
my $tmp3 = "$pwd/$0_3.out";
|
||||
|
||||
my ($c,@i);
|
||||
my $tpl = Tpl->tpl_map("A(S(ci#))",\$c,\@i,10);
|
||||
|
||||
# make element 1
|
||||
$c = 97;
|
||||
@i = (0,1,2,3,4,5,6,7,8,9);
|
||||
$tpl->tpl_pack(1);
|
||||
|
||||
# make element 2
|
||||
$c = 98;
|
||||
@i = (1,2,3,4,5,6,7,8,9,10);
|
||||
$tpl->tpl_pack(1);
|
||||
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
|
||||
`../tplxml $tmp1 > $tmp2`; # convert tpl to xml
|
||||
`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl
|
||||
`diff $tmp1 $tmp3`;
|
||||
print "tpl files ", ($? ? "differ" : "identical"), "\n";
|
||||
|
1
lang/perl/tests/test20.ans
Normal file
@ -0,0 +1 @@
|
||||
tpl files identical
|
15
lang/perl/tests/test21
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
my $fmt = Tpl->tpl_peek(\$img);
|
||||
print("$fmt\n");
|
1
lang/perl/tests/test21.ans
Normal file
@ -0,0 +1 @@
|
||||
A(i)
|
21
lang/perl/tests/test22
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my @i=(1,2,3,4);
|
||||
my @j=(-1,-2,-3, -4);
|
||||
my $tpl = Tpl->tpl_map("i#i#",\@i, 3, \@j, 4);
|
||||
$tpl->tpl_pack(0);
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my $fmt = Tpl->tpl_peek($tmp1);
|
||||
print "$fmt\n";
|
1
lang/perl/tests/test22.ans
Normal file
@ -0,0 +1 @@
|
||||
i#i#
|
21
lang/perl/tests/test23
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
# this test only works on 64-bit Perl
|
||||
|
||||
my ($i,$j) = (-4294967296,4294967296); # 2^32 (can't fit in a 32-bit value)
|
||||
my $tpl = Tpl->tpl_map("IU",\$i,\$j);
|
||||
$tpl->tpl_pack(0);
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
my ($x,$y);
|
||||
my $tpl2 = Tpl->tpl_map("IU",\$x,\$y);
|
||||
$tpl2->tpl_load(\$img);
|
||||
$tpl2->tpl_unpack(0);
|
||||
print "$x $y\n";
|
||||
|
16
lang/perl/tests/test3
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
open TPLXML, "|../tplxml" or die "can't open tplxml: $!";
|
||||
print TPLXML $img;
|
||||
close TPLXML;
|
53
lang/perl/tests/test3.ans
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>
|
||||
<tplxml format="A(i)" fxlens="">
|
||||
<A>
|
||||
<el>
|
||||
<i>0</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>1</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>2</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>3</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>4</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>5</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>6</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>7</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>8</i>
|
||||
</el>
|
||||
<el>
|
||||
<i>9</i>
|
||||
</el>
|
||||
</A>
|
||||
</tplxml>
|
26
lang/perl/tests/test4
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
my $tmp2 = "$pwd/$0_2.out";
|
||||
my $tmp3 = "$pwd/$0_3.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(i)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
|
||||
`../tplxml $tmp1 > $tmp2`; # convert tpl to xml
|
||||
`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl
|
||||
`diff $tmp1 $tmp3`;
|
||||
print "tpl files ", ($? ? "differ" : "identical"), "\n";
|
||||
|
1
lang/perl/tests/test4.ans
Normal file
@ -0,0 +1 @@
|
||||
tpl files identical
|
23
lang/perl/tests/test5
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(c)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(c)",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
while($tpl2->tpl_unpack(1) > 0) { printf("%d\n", $j); }
|
||||
|
10
lang/perl/tests/test5.ans
Normal file
@ -0,0 +1,10 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
16
lang/perl/tests/test6
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(c)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
my $img = $tpl->tpl_dump();
|
||||
|
||||
open TPLXML, "|../tplxml" or die "can't open tplxml: $!";
|
||||
print TPLXML $img;
|
||||
close TPLXML;
|
53
lang/perl/tests/test6.ans
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>
|
||||
<tplxml format="A(c)" fxlens="">
|
||||
<A>
|
||||
<el>
|
||||
<c>0</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>1</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>2</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>3</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>4</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>5</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>6</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>7</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>8</c>
|
||||
</el>
|
||||
<el>
|
||||
<c>9</c>
|
||||
</el>
|
||||
</A>
|
||||
</tplxml>
|
26
lang/perl/tests/test7
Executable file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
my $tmp2 = "$pwd/$0_2.out";
|
||||
my $tmp3 = "$pwd/$0_3.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(c)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
|
||||
`../tplxml $tmp1 > $tmp2`; # convert tpl to xml
|
||||
`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl
|
||||
`diff $tmp1 $tmp3`;
|
||||
print "tpl files ", ($? ? "differ" : "identical"), "\n";
|
||||
|
1
lang/perl/tests/test7.ans
Normal file
@ -0,0 +1 @@
|
||||
tpl files identical
|
29
lang/perl/tests/test8
Executable file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
my $tmp2 = "$pwd/$0_2.out";
|
||||
my $tmp3 = "$pwd/$0_3.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(s)",\$i);
|
||||
for (qw(normal has&ersand <anglebrackets>)) {
|
||||
$i = $_;
|
||||
$tpl->tpl_pack(1);
|
||||
}
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
|
||||
`../tplxml $tmp1 > $tmp2`; # convert tpl to xml
|
||||
`../tplxml $tmp2 > $tmp3`; # convert xml back to tpl
|
||||
`diff $tmp1 $tmp3`;
|
||||
print "tpl files ", ($? ? "differ" : "identical"), "\n";
|
||||
|
1
lang/perl/tests/test8.ans
Normal file
@ -0,0 +1 @@
|
||||
tpl files identical
|
23
lang/perl/tests/test9
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib "..";
|
||||
use Tpl;
|
||||
|
||||
my $pwd = `pwd`;
|
||||
chomp $pwd;
|
||||
|
||||
my $tmp1 = "$pwd/$0_1.out";
|
||||
|
||||
my $i;
|
||||
my $tpl = Tpl->tpl_map("A(u)",\$i);
|
||||
for($i=0; $i<10; $i++) { $tpl->tpl_pack(1); }
|
||||
$tpl->tpl_dump($tmp1);
|
||||
|
||||
my $j;
|
||||
my $tpl2 = Tpl->tpl_map("A(u)",\$j);
|
||||
$tpl2->tpl_load($tmp1);
|
||||
while($tpl2->tpl_unpack(1) > 0) { print "$j\n" }
|
||||
|
10
lang/perl/tests/test9.ans
Normal file
@ -0,0 +1,10 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
24
lang/perl/tplfmt
Executable file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# tplfmt
|
||||
# by Troy Hanson Feb 2006
|
||||
# print the format string of a tpl image file
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub peek_fmt {
|
||||
my $buf = shift;
|
||||
die "invalid tpl file" unless ($$buf =~ /^tpl/);
|
||||
return (unpack("Z*", substr($$buf,8)));
|
||||
}
|
||||
|
||||
die "usage: $0 <file> [<file> ...]" unless (@ARGV > 0);
|
||||
|
||||
undef $/; # slurp
|
||||
for (@ARGV) {
|
||||
open TPL, "<$_" or die "can't open $_: $!";
|
||||
my $tpl = <TPL>;
|
||||
print "$_: ", peek_fmt(\$tpl), "\n";
|
||||
close TPL;
|
||||
}
|
306
lang/perl/tplxml
Executable file
@ -0,0 +1,306 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# tplxml
|
||||
# by Troy Hanson 27 Feb 2006
|
||||
# convert between tpl and XML
|
||||
|
||||
# Copyright (c) 2005-2006, Troy Hanson http://tpl.sourceforge.net
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use XML::Parser;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin"; #locate Tpl.pm in same directory as tplxml
|
||||
use Tpl;
|
||||
use bytes;
|
||||
|
||||
sub quote_chars {
|
||||
my $str = shift;
|
||||
$$str =~ s/&/&/g; #order matters
|
||||
$$str =~ s/</</g;
|
||||
$$str =~ s/>/>/g;
|
||||
}
|
||||
sub unquote_chars {
|
||||
my $str = shift;
|
||||
$$str =~ s/</</g;
|
||||
$$str =~ s/>/>/g;
|
||||
$$str =~ s/&/&/g;
|
||||
}
|
||||
sub hex_chars {
|
||||
my $str = shift;
|
||||
my $hex;
|
||||
for(my $i=0; $i < length $$str; $i++) {
|
||||
my $byte = unpack("C",substr($$str,$i,1));
|
||||
$hex .= sprintf("%02x", $byte);
|
||||
}
|
||||
$$str = $hex;
|
||||
}
|
||||
sub unhex_chars {
|
||||
my $str = shift;
|
||||
my $bytes;
|
||||
for(my $i=0; $i < length $$str; $i+=2) {
|
||||
my $hexbyte = substr($$str,$i,2);
|
||||
$bytes .= pack("C", hex($hexbyte));
|
||||
}
|
||||
$$str= $bytes;
|
||||
}
|
||||
|
||||
sub tpl2xml {
|
||||
my $src = shift;
|
||||
my (@out,@args);
|
||||
|
||||
# build list of references to hold output of unpacking
|
||||
my ($fmt,@fxlens) = peek_fmt($src);
|
||||
for(my ($i,$j,$k)=(0,0,0);$i<length($fmt);$i++) {
|
||||
push @args, [] if substr($fmt,$i,2) =~ /^[iucfIU]\#$/; # octothorpic
|
||||
push @args, \$out[$j++] if substr($fmt,$i,2) =~ /^[iuBscfIU][^\#]*$/;
|
||||
push @args, $fxlens[$k++] if substr($fmt,$i,1) eq "#";
|
||||
}
|
||||
|
||||
my $tpl = Tpl->tpl_map($fmt,@args);
|
||||
$tpl->tpl_load($src);
|
||||
$tpl->tpl_unpack(0);
|
||||
|
||||
# construct xml preamble
|
||||
my $pre = qq{<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE tplxml [
|
||||
<!ELEMENT tplxml (A|i|u|I|U|B|s|c|f|fx)*>
|
||||
<!ATTLIST tplxml
|
||||
format CDATA #REQUIRED
|
||||
fxlens CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT i (#PCDATA)>
|
||||
<!ELEMENT u (#PCDATA)>
|
||||
<!ELEMENT I (#PCDATA)>
|
||||
<!ELEMENT U (#PCDATA)>
|
||||
<!ELEMENT B (#PCDATA)>
|
||||
<!ELEMENT s (#PCDATA)>
|
||||
<!ELEMENT c (#PCDATA)>
|
||||
<!ELEMENT f (#PCDATA)>
|
||||
<!ELEMENT A (el)*>
|
||||
<!ELEMENT el (A|i|u|I|U|B|s|c|f|fx)+>
|
||||
<!ELEMENT fx (i|u|I|U|c|f)*>
|
||||
]>\n};
|
||||
print $pre;
|
||||
my $fxattr = join ",", @fxlens;
|
||||
print qq{<tplxml format="$fmt" fxlens="$fxattr">\n};
|
||||
tpl2xml_node($tpl,"A0",1);
|
||||
print qq{</tplxml>\n};
|
||||
}
|
||||
|
||||
sub tpl2xml_node {
|
||||
my $tpl = shift;
|
||||
my $node = shift;
|
||||
my $indent = shift;
|
||||
my $i = " " x $indent;
|
||||
for my $c (@{ $tpl->{$node} }) {
|
||||
if (ref($c)) {
|
||||
my ($type,$addr,$fxlen) = @$c;
|
||||
quote_chars $addr if $type eq 's';
|
||||
hex_chars $addr if $type eq 'B';
|
||||
if (not defined $fxlen) {
|
||||
print qq{$i<$type>$$addr</$type>\n}; # singleton
|
||||
} else {
|
||||
# all elements of octothorpic fixed-len array
|
||||
print qq{$i<fx>\n};
|
||||
print qq{$i <$type>$addr->[$_]</$type>\n} for (0..$fxlen-1);
|
||||
print qq{$i</fx>\n};
|
||||
}
|
||||
} else {
|
||||
# A node
|
||||
print qq{$i<A>\n};
|
||||
my $idx = $1 if $c =~ /^A(\d+)$/;
|
||||
while($tpl->tpl_unpack($idx) > 0) {
|
||||
print qq{$i<el>\n};
|
||||
tpl2xml_node($tpl,$c,$indent+1);
|
||||
print qq{$i</el>\n};
|
||||
}
|
||||
print qq{$i</A>\n};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub xml2tpl {
|
||||
my $src = shift;
|
||||
my $p = new XML::Parser( Style => 'Tree' );
|
||||
my $tree = $p->parse($$src);
|
||||
die "not a tpl xml document" unless $tree->[0] eq 'tplxml';
|
||||
die "no format attribute" unless defined $tree->[1][0]->{format};
|
||||
my $fmt = $tree->[1][0]->{format};
|
||||
die "no fxlens attribute" unless defined $tree->[1][0]->{fxlens};
|
||||
my @fxlens = split /,/, $tree->[1][0]->{fxlens};
|
||||
|
||||
# build list of references to variables for use in packing
|
||||
my (@args,@out);
|
||||
for(my ($i,$j,$k)=(0,0,0);$i<length($fmt);$i++) {
|
||||
push @args, [] if substr($fmt,$i,2) =~ /^[iucfIU]\#$/; # octothorpic
|
||||
push @args, \$out[$j++] if substr($fmt,$i,2) =~ /^[iuBscfIU][^\#]*$/;
|
||||
push @args, $fxlens[$k++] if substr($fmt,$i,1) eq "#";
|
||||
}
|
||||
|
||||
my $tpl = Tpl->tpl_map($fmt,@args);
|
||||
xml2tpl_dfs($tpl,$tree->[1]);
|
||||
$tpl->tpl_pack(0);
|
||||
print $tpl->tpl_dump;
|
||||
}
|
||||
|
||||
sub xml2tpl_dfs {
|
||||
my $tpl = shift;
|
||||
my $xml = shift;
|
||||
|
||||
my @next = @$xml; # ($attr,@tagvals) = $$xml;
|
||||
shift @next; # discard <tplxml> attributes
|
||||
my @tpltoks = @{ $tpl->{"A0"} }; #expected tokens when parsing
|
||||
|
||||
TAG: while (@next) {
|
||||
my $xmltag = shift @next;
|
||||
my $xmlval = shift @next;
|
||||
|
||||
# skip whitespace/newlines embedded between tags
|
||||
next TAG if ($xmltag eq "0" and $xmlval =~ /^\s+$/);
|
||||
|
||||
# pack if necessary. consume tokens by look-ahead until non-pack token.
|
||||
while (@tpltoks > 0 and $tpltoks[0] =~ /^P(\d+)$/) {
|
||||
shift @tpltoks;
|
||||
$tpl->tpl_pack($1);
|
||||
}
|
||||
|
||||
# If tpl format specifies a non-array type should appear at this point
|
||||
# in the XML tree, then validate the type matches the format and assign
|
||||
# the value from the XML to the variable from which it'll be packed
|
||||
my $tpltoken = shift @tpltoks;
|
||||
my $octothorpic=0;
|
||||
if (ref $tpltoken) {
|
||||
my ($tpltype,$tpladdr,$fxlen) = @$tpltoken;
|
||||
|
||||
# This block is how we handle octothorpic (fixed length) arrays.
|
||||
# If $fxlen is defined then an octothorpic <fx> node is expected.
|
||||
# After finding the <fx> node we put its subnodes (the array elements)
|
||||
# onto the @next array for immediate parsing and we use $fxlen:$remaining
|
||||
# as a signet version of the $fxlen to induce the element-processing loop.
|
||||
if (defined $fxlen) {
|
||||
if ($fxlen =~ /^(\d+):(\d+)$/) { # $1==orig $fxlen, $2==remain $fxlen
|
||||
$octothorpic=1;
|
||||
unshift @tpltoks, [$tpltype, $tpladdr, $1.":".($2-1)] if $2 > 1;
|
||||
} else { # octothorpic array expected; look for <fx> parent node
|
||||
die "expected '<fx>' but got '<$xmltag>'" unless $xmltag eq 'fx';
|
||||
@{ $tpladdr } = (); # Empty accumulator array for octothorpic values
|
||||
unshift @tpltoks, [$tpltype, $tpladdr, "$fxlen:$fxlen"]; # x:x signet
|
||||
shift @$xmlval; # discard 'A' attributes
|
||||
unshift @next, @$xmlval; #parse xml subtree now (dfs)
|
||||
next TAG; # proceed to children of <fx> node
|
||||
}
|
||||
}
|
||||
|
||||
if ($tpltype ne $xmltag) {
|
||||
die "mismatch: xml has '$xmltag' where format specifies '$tpltype'";
|
||||
}
|
||||
# expect @$xmlval to be ({},0,'value') i.e. a single, terminal text node
|
||||
if (@$xmlval > 3 || $xmlval->[1] ne '0') {
|
||||
die "error: xml tag '$xmltag' cannot enclose sub-tags";
|
||||
}
|
||||
if ($octothorpic) {
|
||||
push @{ $tpladdr }, $xmlval->[2];
|
||||
} else {
|
||||
$$tpladdr = $xmlval->[2];
|
||||
}
|
||||
unquote_chars $tpladdr if $tpltype eq 's';
|
||||
unhex_chars $tpladdr if $tpltype eq 'B';
|
||||
} elsif ($tpltoken =~ /^A(\d+)$/) {
|
||||
# tpl format specifies an array should appear at this point in the XML
|
||||
if ($xmltag ne 'A') {
|
||||
die "mismatch: xml has '$xmltag' where format specifies 'A'";
|
||||
}
|
||||
shift @$xmlval; # discard 'A' attributes
|
||||
|
||||
# form token that means "replace me with tokens from A(n), x times"
|
||||
# (where x is the number of elements contained by this array).
|
||||
my $array_count=0;
|
||||
for(my $i=0; $i < @$xmlval; $i+=2) {
|
||||
$array_count++ if $xmlval->[$i] eq 'el';
|
||||
}
|
||||
|
||||
unshift @tpltoks, "N$1:$array_count" if $array_count > 0;
|
||||
unshift @next, @$xmlval; #parse xml subtree now (dfs)
|
||||
} elsif ($tpltoken =~ /^N(\d+):(\d+)$/) {
|
||||
if ($xmltag ne "el") {
|
||||
die "mismatch: xml has '$xmltag' where array 'el' is expected";
|
||||
}
|
||||
# prepend A$1's tokens (and decremented N:count) to expected tokens
|
||||
my ($n,$elsleft) = ($1, ($2 - 1));
|
||||
unshift @tpltoks, "N$n:$elsleft" if $elsleft > 0;
|
||||
unshift @tpltoks, "P$n"; # "pack me now" token
|
||||
unshift @tpltoks, @{ $tpl->{"A$1"} };
|
||||
|
||||
shift @$xmlval; # discard 'el' attributes
|
||||
unshift @next, @$xmlval; # proceed to parse el subtree (dfs)
|
||||
} else {
|
||||
die "internal error, unexpected token $tpltoken";
|
||||
}
|
||||
}
|
||||
|
||||
# pack if necessary. consume tokens by look-ahead until non-pack token.
|
||||
while (@tpltoks > 0 and $tpltoks[0] =~ /^P(\d+)$/) {
|
||||
shift @tpltoks;
|
||||
$tpl->tpl_pack($1);
|
||||
}
|
||||
|
||||
if (@tpltoks > 0) {
|
||||
die "error: end of xml document reached but format requires more data";
|
||||
}
|
||||
}
|
||||
|
||||
sub peek_fmt {
|
||||
my $buf = shift;
|
||||
die "invalid tpl file" unless ($$buf =~ /^tpl/);
|
||||
my $flags = CORE::unpack("C", substr($$buf,3,1));
|
||||
my $UF = ($flags & 1) ? "N" : "V"; # big or little endian fxlens
|
||||
my $fmt = (CORE::unpack("Z*", substr($$buf,8)));
|
||||
my $num_octothorpes = scalar (my @o = ($fmt =~ /#/g));
|
||||
my @fxlens;
|
||||
my $fx = 8 + length($fmt) + 1;
|
||||
for(my $i=0; $i < $num_octothorpes; $i++) {
|
||||
my $fxlen_bytes = substr($$buf,$fx,4);
|
||||
my $fxlen = unpack($UF, $fxlen_bytes);
|
||||
push @fxlens, $fxlen;
|
||||
$fx += 4;
|
||||
}
|
||||
return ($fmt,@fxlens);
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# Slurp input file, auto-detect if conversion is to tpl or XML, and run.
|
||||
##########################################################################
|
||||
|
||||
undef $/;
|
||||
my $src = <>;
|
||||
our $to = (substr($src,0,3) eq "tpl") ? "xml" : "tpl";
|
||||
xml2tpl(\$src) if $to eq "tpl";
|
||||
tpl2xml(\$src) if $to eq "xml";
|
||||
|
7
src/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
SUBDIRS = win
|
||||
lib_LTLIBRARIES = libtpl.la
|
||||
libtpl_la_SOURCES = tpl.c
|
||||
include_HEADERS = tpl.h
|
||||
libtpl_la_LDFLAGS = -no-undefined -version-info 0:0:0
|
||||
libtpl_la_LIBADD = win/libwinmmap.la
|
||||
|
137
src/tpl.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (c) 2005-2010, Troy D. Hanson http://tpl.sourceforge.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TPL_H
|
||||
#define TPL_H
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#include <tbb/tbbmalloc_proxy.h>
|
||||
#endif /* Intel Compiler efficient memcpy etc */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#include <inttypes.h> /* uint32_t */
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef TPL_EXPORTS
|
||||
#define TPL_API __declspec(dllexport)
|
||||
#else /* */
|
||||
#ifdef TPL_NOLIB
|
||||
#define TPL_API
|
||||
#else
|
||||
#define TPL_API __declspec(dllimport)
|
||||
#endif /* TPL_NOLIB */
|
||||
#endif /* TPL_EXPORTS*/
|
||||
#else
|
||||
#define TPL_API
|
||||
#endif
|
||||
|
||||
/* bit flags (external) */
|
||||
#define TPL_FILE (1 << 0)
|
||||
#define TPL_MEM (1 << 1)
|
||||
#define TPL_PREALLOCD (1 << 2)
|
||||
#define TPL_EXCESS_OK (1 << 3)
|
||||
#define TPL_FD (1 << 4)
|
||||
#define TPL_UFREE (1 << 5)
|
||||
#define TPL_DATAPEEK (1 << 6)
|
||||
#define TPL_FXLENS (1 << 7)
|
||||
#define TPL_GETSIZE (1 << 8)
|
||||
/* do not add flags here without renumbering the internal flags! */
|
||||
|
||||
/* flags for tpl_gather mode */
|
||||
#define TPL_GATHER_BLOCKING 1
|
||||
#define TPL_GATHER_NONBLOCKING 2
|
||||
#define TPL_GATHER_MEM 3
|
||||
|
||||
/* Hooks for error logging, memory allocation functions and fatal */
|
||||
typedef int (tpl_print_fcn)(const char *fmt, ...);
|
||||
typedef void *(tpl_malloc_fcn)(size_t sz);
|
||||
typedef void *(tpl_realloc_fcn)(void *ptr, size_t sz);
|
||||
typedef void (tpl_free_fcn)(void *ptr);
|
||||
typedef void (tpl_fatal_fcn)(const char *fmt, ...);
|
||||
|
||||
typedef struct tpl_hook_t {
|
||||
tpl_print_fcn *oops;
|
||||
tpl_malloc_fcn *malloc;
|
||||
tpl_realloc_fcn *realloc;
|
||||
tpl_free_fcn *free;
|
||||
tpl_fatal_fcn *fatal;
|
||||
size_t gather_max;
|
||||
} tpl_hook_t;
|
||||
|
||||
typedef struct tpl_node {
|
||||
int type;
|
||||
void *addr;
|
||||
void *data; /* r:tpl_root_data*. A:tpl_atyp*. ow:szof type */
|
||||
int num; /* length of type if its a C array */
|
||||
size_t ser_osz; /* serialization output size for subtree */
|
||||
struct tpl_node *children; /* my children; linked-list */
|
||||
struct tpl_node *next,*prev; /* my siblings (next child of my parent) */
|
||||
struct tpl_node *parent; /* my parent */
|
||||
} tpl_node;
|
||||
|
||||
/* used when un/packing 'B' type (binary buffers) */
|
||||
typedef struct tpl_bin {
|
||||
void *addr;
|
||||
uint32_t sz;
|
||||
} tpl_bin;
|
||||
|
||||
/* for async/piecemeal reading of tpl images */
|
||||
typedef struct tpl_gather_t {
|
||||
char *img;
|
||||
int len;
|
||||
} tpl_gather_t;
|
||||
|
||||
/* Callback used when tpl_gather has read a full tpl image */
|
||||
typedef int (tpl_gather_cb)(void *img, size_t sz, void *data);
|
||||
|
||||
/* Prototypes */
|
||||
TPL_API tpl_node *tpl_map(char *fmt,...); /* define tpl using format */
|
||||
TPL_API void tpl_free(tpl_node *r); /* free a tpl map */
|
||||
TPL_API int tpl_pack(tpl_node *r, int i); /* pack the n'th packable */
|
||||
TPL_API int tpl_unpack(tpl_node *r, int i); /* unpack the n'th packable */
|
||||
TPL_API int tpl_dump(tpl_node *r, int mode, ...); /* serialize to mem/file */
|
||||
TPL_API int tpl_load(tpl_node *r, int mode, ...); /* set mem/file to unpack */
|
||||
TPL_API int tpl_Alen(tpl_node *r, int i); /* array len of packable i */
|
||||
TPL_API char* tpl_peek(int mode, ...); /* sneak peek at format string */
|
||||
TPL_API int tpl_gather( int mode, ...); /* non-blocking image gather */
|
||||
TPL_API int tpl_jot(int mode, ...); /* quick write a simple tpl */
|
||||
|
||||
TPL_API tpl_node *tpl_map_va(char *fmt, va_list ap);
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TPL_H */
|
||||
|
4
src/win/Makefile.am
Normal file
@ -0,0 +1,4 @@
|
||||
noinst_LTLIBRARIES = libwinmmap.la
|
||||
noinst_HEADERS = mman.h
|
||||
libwinmmap_la_SOURCES = nonempty.c
|
||||
libwinmmap_la_LIBADD = @LTLIBOBJS@
|
11
src/win/README
Normal file
@ -0,0 +1,11 @@
|
||||
This directory contains functions that are missing on the Windows platform. In
|
||||
particular, mmap, munmap, and msync are not available on Windows. These
|
||||
replacements are used on both Cygwin and MinGW. (On Cygwin the built-in mmap
|
||||
has no write support, and is not used).
|
||||
|
||||
mmap.c
|
||||
mman.h
|
||||
|
||||
Special thanks to Horea Haitonic for contributing mmap.c and mman.h.
|
||||
|
||||
April 2007
|
52
src/win/mman.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef _MMAN_H_
|
||||
#define _MMAN_H_
|
||||
|
||||
/* Protections */
|
||||
#define PROT_NONE 0x00 /* no permissions */
|
||||
#define PROT_READ 0x01 /* pages can be read */
|
||||
#define PROT_WRITE 0x02 /* pages can be written */
|
||||
#define PROT_EXEC 0x04 /* pages can be executed */
|
||||
|
||||
/* Sharing type and options */
|
||||
#define MAP_SHARED 0x0001 /* share changes */
|
||||
#define MAP_PRIVATE 0x0002 /* changes are private */
|
||||
#define MAP_COPY MAP_PRIVATE /* Obsolete */
|
||||
#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */
|
||||
#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
|
||||
#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
|
||||
#define MAP_INHERIT 0x0080 /* region is retained after exec */
|
||||
#define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
|
||||
#define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */
|
||||
#define MAP_STACK 0x0400 /* region grows down, like a stack */
|
||||
|
||||
/* Error returned from mmap() */
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
|
||||
/* Flags to msync */
|
||||
#define MS_ASYNC 0x01 /* perform asynchronous writes */
|
||||
#define MS_SYNC 0x02 /* perform synchronous writes */
|
||||
#define MS_INVALIDATE 0x04 /* invalidate cached data */
|
||||
|
||||
/* File modes for 'open' not defined in MinGW32 (not used by mmap) */
|
||||
#ifndef S_IWGRP
|
||||
#define S_IWGRP 0
|
||||
#define S_IRGRP 0
|
||||
#define S_IROTH 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Map a file to a memory region
|
||||
*/
|
||||
void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset);
|
||||
|
||||
/**
|
||||
* Unmap a memory region
|
||||
*/
|
||||
int munmap(void *addr, int len);
|
||||
|
||||
/**
|
||||
* Synchronize a mapped region
|
||||
*/
|
||||
int msync(char *addr, int len, int flags);
|
||||
|
||||
#endif /* _MMAN_H_ */
|
171
src/win/mmap.c
Normal file
@ -0,0 +1,171 @@
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include "mman.h"
|
||||
|
||||
static const char id[]="$Id: tpl.c 107 2007-04-20 17:11:29Z thanson $";
|
||||
|
||||
/**
|
||||
* @brief Map a file to a memory region
|
||||
*
|
||||
* This function emulates the POSIX mmap() using CreateFileMapping() and
|
||||
* MapViewOfFile()
|
||||
*
|
||||
* @param addr the suggested start address (if != 0)
|
||||
* @param len length of the region
|
||||
* @param prot region accesibility, bitwise OR of PROT_READ, PROT_WRITE, PROT_EXEC
|
||||
* @param flags mapping type and options (ignored)
|
||||
* @param fd object to be mapped into memory
|
||||
* @param offset offset into mapped object
|
||||
* @return pointer to the memory region, or NULL in case of error
|
||||
*/
|
||||
void *mmap(void *addr, unsigned int len, int prot, int flags, int fd, unsigned int offset)
|
||||
{
|
||||
DWORD wprot;
|
||||
DWORD waccess;
|
||||
HANDLE h;
|
||||
void *region;
|
||||
|
||||
/* Translate read/write/exec flags into WIN32 constants */
|
||||
switch (prot) {
|
||||
case PROT_READ:
|
||||
wprot = PAGE_READONLY;
|
||||
break;
|
||||
case PROT_EXEC:
|
||||
wprot = PAGE_EXECUTE_READ;
|
||||
break;
|
||||
case PROT_READ | PROT_EXEC:
|
||||
wprot = PAGE_EXECUTE_READ;
|
||||
break;
|
||||
case PROT_WRITE:
|
||||
wprot = PAGE_READWRITE;
|
||||
break;
|
||||
case PROT_READ | PROT_WRITE:
|
||||
wprot = PAGE_READWRITE;
|
||||
break;
|
||||
case PROT_READ | PROT_WRITE | PROT_EXEC:
|
||||
wprot = PAGE_EXECUTE_READWRITE;
|
||||
break;
|
||||
case PROT_WRITE | PROT_EXEC:
|
||||
wprot = PAGE_EXECUTE_READWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Obtaing handle to map region */
|
||||
h = CreateFileMapping((HANDLE) _get_osfhandle(fd), 0, wprot, 0, len, 0);
|
||||
if (h == NULL) {
|
||||
DWORD error = GetLastError();
|
||||
|
||||
/* Try and translate some error codes */
|
||||
switch (error) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_INVALID_ACCESS:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_OUTOFMEMORY:
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
|
||||
/* Translate sharing options into WIN32 constants */
|
||||
switch (wprot) {
|
||||
case PAGE_READONLY:
|
||||
waccess = FILE_MAP_READ;
|
||||
break;
|
||||
case PAGE_READWRITE:
|
||||
waccess = FILE_MAP_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Map file and return pointer */
|
||||
region = MapViewOfFile(h, waccess, 0, 0, 0);
|
||||
if (region == NULL) {
|
||||
DWORD error = GetLastError();
|
||||
|
||||
/* Try and translate some error codes */
|
||||
switch (error) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_INVALID_ACCESS:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_INVALID_HANDLE:
|
||||
errno = EBADF;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
CloseHandle(h);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
CloseHandle(h); /* ok to call UnmapViewOfFile after this */
|
||||
|
||||
/* All fine */
|
||||
return region;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Unmap a memory region
|
||||
*
|
||||
* This is a wrapper around UnmapViewOfFile in the win32 API
|
||||
*
|
||||
* @param addr start address
|
||||
* @param len length of the region
|
||||
* @return 0 for success, -1 for error
|
||||
*/
|
||||
int munmap(void *addr, int len)
|
||||
{
|
||||
if (UnmapViewOfFile(addr)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Synchronize a mapped region
|
||||
*
|
||||
* This is a wrapper around FlushViewOfFile
|
||||
*
|
||||
* @param addr start address
|
||||
* @param len number of bytes to flush
|
||||
* @param flags sync options -- currently ignored
|
||||
* @return 0 for success, -1 for error
|
||||
*/
|
||||
int msync(char *addr, int len, int flags)
|
||||
{
|
||||
if (FlushViewOfFile(addr, len) == 0) {
|
||||
DWORD error = GetLastError();
|
||||
|
||||
/* Try and translate some error codes */
|
||||
switch (error) {
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case ERROR_WRITE_FAULT:
|
||||
errno = EIO;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
6
src/win/nonempty.c
Normal file
@ -0,0 +1,6 @@
|
||||
/* This function exists solely to prevent libwinmmap.la from being empty. Empty
|
||||
* libraries cause problems on some platforms, e.g. Mac OS X. */
|
||||
|
||||
int tpl_nonempty(int i) {
|
||||
return i+1;
|
||||
}
|
88
tests/Makefile
Normal file
@ -0,0 +1,88 @@
|
||||
# Makefile for tpl built-in test suite
|
||||
#
|
||||
# This Makefile has three useful targets:
|
||||
#
|
||||
# all (default):
|
||||
# Build and run all self-tests by compiling tpl into each test.
|
||||
#
|
||||
# Note: On Cygwin/MinGW, compiling the tpl source directly into the tests is
|
||||
# not supported (as they use 'replacement' functions which get included only
|
||||
# in libtpl), so on these platforms the 'alt' target is the default.
|
||||
#
|
||||
# alt:
|
||||
# Build and run all the self-tests by linking them with libtpl, which must
|
||||
# have been created beforehand (by running 'configure; make' in the
|
||||
# top-level directory); a reminder will be printed if you have not done so.
|
||||
#
|
||||
# Note, libtool will create wrappers around each test to accomodate the
|
||||
# pre-installed state of ../src/libtpl.la. In a real program, you'd link
|
||||
# against an installed libtpl.la, and these wrappers would not be used.
|
||||
#
|
||||
# clean:
|
||||
# Clean up all the compiled bits.
|
||||
#
|
||||
PROGS = test1 test2 test3 test4 test5 test6 test7 test8 \
|
||||
test9 test10 test11 test12 test13 test14 test15 test16 \
|
||||
test17 test18 test19 test20 test21 test22 test23 test24 \
|
||||
test25 test26 test27 test28 test29 test30 test31 test32 \
|
||||
test33 test34 test35 test36 test37 test38 test39 test40 \
|
||||
test41 test42 test43 test44 test45 test46 test47 test48 \
|
||||
test49 test50 test51 test52 test53 test54 test55 test56 \
|
||||
test57 test58 test59 test60 test61 test62 test63 test64 \
|
||||
test65 test66 test67 test68 test69 test70 test71 test72 \
|
||||
test73 test74 test75 test76 test77 test78 test79 test80 \
|
||||
test81 test82 test83 test84 test85 test86 test87 test88 \
|
||||
test89 test90 test91 test92 test93 test94 test95 test96 \
|
||||
test97 test98 test99 test100 test101 test102 test103 test104 \
|
||||
test105 test106 test107 test108 test109 test110 test111 test112 \
|
||||
test113 test114 test115 test116 test117 test118 test119 test120 \
|
||||
test121 test122 test123 test124
|
||||
|
||||
TPLSRC = ../src
|
||||
CFLAGS = -I$(TPLSRC) -g
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Wall
|
||||
#CFLAGS += -m32
|
||||
#CFLAGS += -m64
|
||||
CFLAGS += -O3
|
||||
#For testing without C99 feature support
|
||||
#CFLAGS += -std=c89
|
||||
|
||||
# Prefer 64-bit compilation on Mac OS X (not necessary, just faster)
|
||||
ifneq ($(strip $(shell $(CC) -v 2>&1 |egrep "i[0-9]+-apple-darwin")),)
|
||||
CFLAGS += -m64
|
||||
endif
|
||||
|
||||
# detect Cygwin or MinGW
|
||||
ifneq ($(strip $(shell $(CC) -v 2>&1 |egrep "cygwin|mingw")),)
|
||||
TESTS=./do_tests.cygwin
|
||||
# divert to the alt target; use tpl as a lib for Cygwin/Mingw
|
||||
TARGET=alt
|
||||
else
|
||||
TESTS=./do_tests
|
||||
TARGET=$(PROGS) run_tests
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
tpl.o : $(TPLSRC)/tpl.c $(TPLSRC)/tpl.h
|
||||
$(CC) -c $(CFLAGS) $(TPLSRC)/tpl.c
|
||||
|
||||
$(PROGS) : tpl.o
|
||||
$(CC) $(CFLAGS) -o $@ $(@).c tpl.o
|
||||
|
||||
run_tests:
|
||||
perl $(TESTS)
|
||||
|
||||
# This target can be used to compile the tests as dependent on
|
||||
# the tpl library (rather than compiling in the tpl source).
|
||||
alt: mkalttests run_tests
|
||||
|
||||
mkalttests:
|
||||
@$(MAKE) -f Makefile.alt PROGS="$(PROGS)"
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) tpl.o test*.out test*.err test*.exe
|
||||
rm -rf $(PROGS) test*.dSYM
|