aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--Makefile.common3
-rw-r--r--Makefile.dirs2
-rw-r--r--ViCious/pddp/makefile53
-rw-r--r--ViCious/pddp/objects3
-rw-r--r--ViCious/pddp/snapfiles10
-rw-r--r--ViCious/toxy/objects1
-rw-r--r--ViCious/toxy/snapfiles1
-rw-r--r--cyclone/hammer/testmess.c2
-rw-r--r--cyclone/notes.txt2
-rw-r--r--pddp/Makefile10
-rw-r--r--pddp/Makefile.objects3
-rw-r--r--pddp/Makefile.sources3
-rw-r--r--pddp/build_counter7
-rw-r--r--pddp/notes.txt10
-rw-r--r--pddp/pddp-all.exclude8
-rw-r--r--pddp/pddp-help.include0
-rw-r--r--pddp/pddp-shared.include5
-rw-r--r--pddp/pddp-test.exclude5
-rw-r--r--pddp/pddp-vicious.exclude3
-rwxr-xr-xpddp/pddpboot.tcl32
-rw-r--r--pddp/pddpclient.tcl82
-rw-r--r--pddp/pddplink.c136
-rw-r--r--pddp/pddpserver.tcl490
-rw-r--r--test/pddp/pddp.css18
-rw-r--r--test/pddp/pddplink-test-01.html5
-rw-r--r--test/pddp/pddplink-test-01.pd8
-rw-r--r--test/pddp/pddplink-test-01.xml19
-rw-r--r--test/pddp/pddplink-test-02.html5
-rw-r--r--test/pddp/pddplink-test-02.pd8
-rw-r--r--test/pddp/pddplink-test-02.xml19
-rw-r--r--test/pddp/test.bg.jpgbin0 -> 5491 bytes
-rwxr-xr-xtest/pddp/toonepage21
-rwxr-xr-xtest/pddp/topdf23
34 files changed, 996 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 45d67c6..9cd39ec 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ include Makefile.dirs
all:
@for i in $(MIXED_DIRS) ; \
do ( if [ -d $$i ] ; then cd $$i; $(MAKE) ; fi ) ; done
- cd doc/src; $(MAKE)
+ @if [ -d doc/src ] ; then cd doc/src ; $(MAKE) ; fi
clean cleanall:
@for i in $(MIXED_DIRS) ; \
diff --git a/Makefile.common b/Makefile.common
index d106e40..4dd5f25 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -50,7 +50,8 @@ ifeq ($(OS_NAME),MinGW)
CC = gcc
X_SUFFIX = dll
DEFINES = -DNT -DMSW
-OPT_CFLAGS = -funroll-loops
+# assuming pd itself was either vc-compiled or declared -mms-bitfields too...
+OPT_CFLAGS = -funroll-loops -mms-bitfields
LFLAGS = -shared $(PD_DIR)/../bin/pd.dll -Wl,--enable-runtime-pseudo-reloc
endif
diff --git a/Makefile.dirs b/Makefile.dirs
index 8f6e0d9..e5521a0 100644
--- a/Makefile.dirs
+++ b/Makefile.dirs
@@ -2,9 +2,11 @@ MIXED_DIRS = \
shared \
cyclone \
toxy \
+ pddp \
xeq
RELEASE_DIRS = \
cyclone \
toxy \
+ pddp \
xeq
diff --git a/ViCious/pddp/makefile b/ViCious/pddp/makefile
new file mode 100644
index 0000000..fee9c8e
--- /dev/null
+++ b/ViCious/pddp/makefile
@@ -0,0 +1,53 @@
+current: pddp
+
+.SUFFIXES: .dll .obj
+
+ROOTDIR = ..\..\..
+SRCDIR = $(ROOTDIR)\miXed\pddp
+BINDIR = $(ROOTDIR)\miXed\bin
+SHAREDDIR = $(ROOTDIR)\miXed\shared
+EXTDIR = e:\PureData\externals
+PDDIR = e:\PureData\pd
+VCLIBDIR = "e:\Program Files\Microsoft Visual Studio\Vc98\lib"
+ZIPCOMMAND = d:\dosowe\arc\info-zip\zip
+
+INCLUDES = /I. /I$(SHAREDDIR) /I$(PDDIR)\src
+CFLAGS = /W3 /WX /DNT /DMSW /DPD /nologo
+
+LIBS = $(VCLIBDIR)\libc.lib \
+ $(VCLIBDIR)\oldnames.lib \
+ $(VCLIBDIR)\wsock32.lib \
+ $(VCLIBDIR)\kernel32.lib \
+ $(VCLIBDIR)\uuid.lib \
+ $(PDDIR)\bin\pd.lib
+
+!INCLUDE objects
+!INCLUDE snapfiles
+!INCLUDE $(SRCDIR)\build_counter
+
+pddp: pddpboot pddplink.dll
+ @cd $(ROOTDIR)
+ @$(ZIPCOMMAND) pddp-$(PDDP_SNAPSHOT)-dll.zip $(SNAPFILES)
+
+pddpboot:
+ -@copy $(SRCDIR)\pddpboot.tcl $(EXTDIR)
+ -@copy $(SRCDIR)\pddpclient.tcl $(EXTDIR)
+ -@copy $(SRCDIR)\pddpserver.tcl $(EXTDIR)
+ -@copy $(SRCDIR)\pddpboot.tcl $(BINDIR)
+ -@copy $(SRCDIR)\pddpclient.tcl $(BINDIR)
+ -@copy $(SRCDIR)\pddpserver.tcl $(BINDIR)
+
+pddplink.dll: $(PDDPLINK_OBJECTS)
+ -link /dll /out:$@ $(LIBS) $** /export:$(@:.dll=_setup)
+ -@copy $@ $(EXTDIR)
+ -@move $@ $(BINDIR)
+ -del $(@:.dll=.exp)
+ -del $(@:.dll=.lib)
+
+.c.obj: ; cl /c $(CFLAGS) $(INCLUDES) /Fo$*.obj $*.c
+
+clean:
+ del *.obj
+ del *.exp
+ del *.lib
+ del *.dll
diff --git a/ViCious/pddp/objects b/ViCious/pddp/objects
new file mode 100644
index 0000000..85d65b4
--- /dev/null
+++ b/ViCious/pddp/objects
@@ -0,0 +1,3 @@
+PDDPLINK_OBJECTS = $(SRCDIR)\pddplink.obj \
+ $(SHAREDDIR)\common\loud.obj \
+ $(SHAREDDIR)\common\os.obj
diff --git a/ViCious/pddp/snapfiles b/ViCious/pddp/snapfiles
new file mode 100644
index 0000000..9dc4dbd
--- /dev/null
+++ b/ViCious/pddp/snapfiles
@@ -0,0 +1,10 @@
+SNAPFILES = \
+ miXed\bin\pddplink.dll \
+ miXed\bin\pddpboot.tcl \
+ miXed\bin\pddpclient.tcl \
+ miXed\bin\pddpserver.tcl \
+ miXed\ViCious\pddp\makefile \
+ miXed\ViCious\pddp\objects \
+ miXed\ViCious\pddp\snapfiles \
+ miXed\LICENSE.txt \
+ miXed\test\pddp\*.*
diff --git a/ViCious/toxy/objects b/ViCious/toxy/objects
index afe7080..6b7480a 100644
--- a/ViCious/toxy/objects
+++ b/ViCious/toxy/objects
@@ -14,6 +14,7 @@ TOW_OBJECTS = $(SRCDIR)\tow.obj \
WIDGET_OBJECTS = $(SRCDIR)\widget.obj \
$(SRCDIR)\widgettype.obj \
+ $(SRCDIR)\widgethandlers.obj \
$(SHAREDDIR)\unstable\forky.obj \
$(SHAREDDIR)\common\loud.obj \
$(SHAREDDIR)\common\grow.obj \
diff --git a/ViCious/toxy/snapfiles b/ViCious/toxy/snapfiles
index ee0ad69..f2ef4c7 100644
--- a/ViCious/toxy/snapfiles
+++ b/ViCious/toxy/snapfiles
@@ -7,4 +7,5 @@ SNAPFILES = \
miXed\ViCious\toxy\snapfiles \
miXed\LICENSE.txt \
miXed\test\toxy\*.* \
+ miXed\test\toxy\editors\*.* \
miXed\test\toxy\stress\*.*
diff --git a/cyclone/hammer/testmess.c b/cyclone/hammer/testmess.c
index 862e0f1..21ebb7b 100644
--- a/cyclone/hammer/testmess.c
+++ b/cyclone/hammer/testmess.c
@@ -251,7 +251,7 @@ static void testmess_setnames(t_testmess *x, t_symbol *s,
if (natoms > 0 && testmess_makeroom(x, natoms * 2, 0))
{
testmess_setnatoms(x, natoms);
- fragile_class_getnames(x->x_message);
+ fragile_class_getnames(x->x_message, natoms);
}
}
else
diff --git a/cyclone/notes.txt b/cyclone/notes.txt
index 6c62f4c..8ac4f0f 100644
--- a/cyclone/notes.txt
+++ b/cyclone/notes.txt
@@ -1,4 +1,6 @@
TODO for cyclone
+ * add folder class, so people forget about using tot for that purpose
+ * plug import into file/open
DONE for cyclone
diff --git a/pddp/Makefile b/pddp/Makefile
new file mode 100644
index 0000000..b65c310
--- /dev/null
+++ b/pddp/Makefile
@@ -0,0 +1,10 @@
+ROOT_DIR = ..
+redefault: pddpboot default
+
+pddpboot: $(ROOT_DIR)/bin/pddpboot.tcl \
+ $(ROOT_DIR)/bin/pddpclient.tcl $(ROOT_DIR)/bin/pddpserver.tcl
+
+$(ROOT_DIR)/bin/%.tcl: %.tcl
+ cp $< $@
+
+include $(ROOT_DIR)/Makefile.common
diff --git a/pddp/Makefile.objects b/pddp/Makefile.objects
new file mode 100644
index 0000000..3ad9b7a
--- /dev/null
+++ b/pddp/Makefile.objects
@@ -0,0 +1,3 @@
+PDDPLINK_OBJECTS = \
+common/loud.o \
+common/os.o
diff --git a/pddp/Makefile.sources b/pddp/Makefile.sources
new file mode 100644
index 0000000..6349255
--- /dev/null
+++ b/pddp/Makefile.sources
@@ -0,0 +1,3 @@
+TYPES = PDDPLINK
+
+PDDPLINK_SOURCES = pddplink.c
diff --git a/pddp/build_counter b/pddp/build_counter
new file mode 100644
index 0000000..ddd868f
--- /dev/null
+++ b/pddp/build_counter
@@ -0,0 +1,7 @@
+#define PDDP_VERSION "0.1"
+#define PDDP_RELEASE "alpha"
+#define PDDP_BUILD 1
+
+#if 0
+PDDP_SNAPSHOT = 0.1-alpha1
+#endif
diff --git a/pddp/notes.txt b/pddp/notes.txt
new file mode 100644
index 0000000..e156fe1
--- /dev/null
+++ b/pddp/notes.txt
@@ -0,0 +1,10 @@
+TODO for pddp
+ * pddplink:
+ . standardize server's root directory (use $help_directory from pd.tk?)
+ . nonboxed version
+
+DONE for pddp
+
+alpha1
+ * prototype versions of the external "pddplink" and two pd-gui extensions
+ "pddpserver.tcl", "pddpclient.tcl"
diff --git a/pddp/pddp-all.exclude b/pddp/pddp-all.exclude
new file mode 100644
index 0000000..d9e9df1
--- /dev/null
+++ b/pddp/pddp-all.exclude
@@ -0,0 +1,8 @@
+*~
+*.o
+*.gz
+*.html
+*.out
+ref
+ref/*
+dumpsetups
diff --git a/pddp/pddp-help.include b/pddp/pddp-help.include
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pddp/pddp-help.include
diff --git a/pddp/pddp-shared.include b/pddp/pddp-shared.include
new file mode 100644
index 0000000..ab7ac29
--- /dev/null
+++ b/pddp/pddp-shared.include
@@ -0,0 +1,5 @@
+shared/shared.h
+shared/common/loud.c
+shared/common/loud.h
+shared/common/os.c
+shared/common/os.h
diff --git a/pddp/pddp-test.exclude b/pddp/pddp-test.exclude
new file mode 100644
index 0000000..6b3cc43
--- /dev/null
+++ b/pddp/pddp-test.exclude
@@ -0,0 +1,5 @@
+*~
+import-result.pd
+import-debug.pd
+temporary
+temporary/*
diff --git a/pddp/pddp-vicious.exclude b/pddp/pddp-vicious.exclude
new file mode 100644
index 0000000..5e5a82e
--- /dev/null
+++ b/pddp/pddp-vicious.exclude
@@ -0,0 +1,3 @@
+*~
+old
+old/*
diff --git a/pddp/pddpboot.tcl b/pddp/pddpboot.tcl
new file mode 100755
index 0000000..3cec684
--- /dev/null
+++ b/pddp/pddpboot.tcl
@@ -0,0 +1,32 @@
+#!/bin/sh
+# \
+exec tclsh "$0" -- "$@"
+
+# Synopsis
+# test run:
+# ./pddpboot.tcl [root [port [path]]]
+# from Pd:
+# source pddpboot.tcl
+# ::pddp::srvUse root (or ::pddp::srvStart root [port])
+# ::pddp::cliOpen path
+# ... (more "::pddp::cliOpen" calls) ...
+# ::pddp::srvStop
+
+if {[namespace exists ::pddp]} { ;# created by pddplink's setup
+ puts stderr "Booting pddp"
+ set ::pddp::testrun 0
+} else {
+ puts stderr "Booting pddp, test run..."
+ namespace eval ::pddp { variable testrun 1 }
+}
+
+puts stderr "current directory: [pwd]"
+
+source pddpclient.tcl
+source pddpserver.tcl
+
+if {[info exists ::pddp::theDir]} {
+ puts stderr "restoring directory: $::pddp::theDir"
+ cd $::pddp::theDir
+ unset ::pddp::theDir
+}
diff --git a/pddp/pddpclient.tcl b/pddp/pddpclient.tcl
new file mode 100644
index 0000000..7633394
--- /dev/null
+++ b/pddp/pddpclient.tcl
@@ -0,0 +1,82 @@
+# pddpclient.tcl
+
+# Synopsis
+# not to be run by itself (see pddpboot.tcl)
+
+if {![namespace exists ::pddp]} {
+ puts stderr "Error: invalid invocation of pddpclient (boot pddp first)"
+ puts stderr "exiting..."
+ exit 1
+}
+
+if {$::pddp::testrun} { ;# true if sourced from standalone "pddpboot.tcl"
+ puts stderr "Loading pddpclient, test run..."
+ if {$argc > 3} {
+ set path [lindex $argv 3]
+ if {[string length $path]} {
+ puts stderr "Scheduling \"$path\" for opening"
+ after idle ::pddp::cliOpen $path
+ }
+ unset path
+ }
+} else {
+ puts stderr "Loading pddpclient"
+}
+
+namespace eval ::pddp {
+ variable theBrowserCommand
+
+ switch -- $::tcl_platform(platform) {
+ unix {
+ switch -- $tcl_platform(os) {
+ Darwin {
+ set theBrowserCommand "sh -c open %s"
+ }
+ Linux {
+ foreach candidate \
+ {firefox mozilla galeon konqueror netscape lynx} {
+ set browser [lindex [auto_execok $candidate] 0]
+ if {[string length $browser]} {
+ set theBrowserCommand "$browser %s &"
+ break
+ }
+ }
+ }
+ }
+ }
+ windows {
+ # should not this be just: [auto_execok start]?
+ set theBrowserCommand \
+ "rundll32 url.dll,FileProtocolHandler file:%s &"
+ }
+ }
+}
+
+proc ::pddp::cliError {err} {
+ puts stderr "Error in pddpclient: $err"
+}
+
+proc ::pddp::cliOpen {path} {
+ if {[string first "://" $path] < 1} {
+ if {[info exists ::pddp::thePort]} {
+ set path "http://localhost:$::pddp::thePort/$path"
+ } else {
+ cliError "pddpserver not running"
+ return
+ }
+ }
+ variable theBrowserCommand
+ if {[string length $theBrowserCommand]} {
+ set command [format $theBrowserCommand $path]
+ puts stderr "pddpclient: open $command"
+ if {[catch {eval [list exec] $command} err]} {
+ if {[lindex $::errorCode 0] eq "CHILDSTATUS"} {
+ cliError "$err (child status [lindex $::errorCode 2])"
+ } else {
+ cliError $err
+ }
+ }
+ } else {
+ cliError "browser unavailable"
+ }
+}
diff --git a/pddp/pddplink.c b/pddp/pddplink.c
new file mode 100644
index 0000000..d60a90a
--- /dev/null
+++ b/pddp/pddplink.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2005 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#include "m_pd.h"
+#include "m_imp.h" /* FIXME need access to c_externdir... */
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "build_counter"
+
+#ifdef KRZYSZCZ
+//#define PDDPLINK_DEBUG
+#endif
+
+enum { PDDPLINK_PD, PDDPLINK_HTML }; /* LATER add others */
+
+typedef struct _pddplink
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ int x_isboxed;
+ t_symbol *x_dirsym;
+ t_symbol *x_ulink;
+ t_atom x_openargs[2];
+ int x_linktype;
+ int x_ishit;
+} t_pddplink;
+
+static t_class *pddplink_class;
+
+/* FIXME need access to glob_pdobject... */
+static t_pd *pddplink_pdtarget(t_pddplink *x)
+{
+ t_pd *pdtarget = gensym("pd")->s_thing;
+ if (pdtarget && !strcmp(class_getname(*pdtarget), "pd"))
+ return (pdtarget);
+ else
+ return ((t_pd *)x); /* internal error */
+}
+
+static void pddplink_anything(t_pddplink *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_ishit)
+ {
+ startpost("pddplink: internal error (%s", (s ? s->s_name : ""));
+ postatom(ac, av);
+ post(")");
+ }
+}
+
+static void pddplink_click(t_pddplink *x, t_floatarg xpos, t_floatarg ypos,
+ t_floatarg shift, t_floatarg ctrl, t_floatarg alt)
+{
+ x->x_ishit = 1;
+ switch (x->x_linktype)
+ {
+ case PDDPLINK_PD:
+ typedmess(pddplink_pdtarget(x), gensym("open"), 2, x->x_openargs);
+ break;
+ case PDDPLINK_HTML:
+ sys_vgui("after 0 {::pddp::cliOpen %s}\n", x->x_ulink->s_name);
+ break;
+ }
+ x->x_ishit = 0;
+}
+
+#ifdef PDDPLINK_DEBUG
+static void pddplink_debug(t_pddplink *x)
+{
+}
+#endif
+
+static void pddplink_free(t_pddplink *x)
+{
+}
+
+static void *pddplink_new(t_symbol *s1, t_symbol *s2)
+{
+ t_pddplink *x = (t_pddplink *)pd_new(pddplink_class);
+ t_symbol *dirsym;
+ x->x_glist = canvas_getcurrent();
+ x->x_isboxed = (s2 == gensym("box"));
+ x->x_dirsym = canvas_getdir(x->x_glist); /* FIXME */
+ if (!s1 || s1 == &s_)
+ {
+ x->x_linktype = PDDPLINK_HTML;
+ x->x_ulink = gensym("index.html");
+ }
+ else
+ {
+ int len = strlen(s1->s_name);
+ if (len > 3 && !strcmp(s1->s_name + len - 3, ".pd"))
+ x->x_linktype = PDDPLINK_PD;
+ else
+ x->x_linktype = PDDPLINK_HTML;
+ x->x_ulink = s1;
+ }
+ SETSYMBOL(&x->x_openargs[0], x->x_ulink);
+ SETSYMBOL(&x->x_openargs[1], x->x_dirsym);
+ x->x_ishit = 0;
+ if (x->x_isboxed)
+ {
+ inlet_new((t_object *)x, (t_pd *)x, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ }
+ if (x->x_linktype == PDDPLINK_HTML)
+ sys_vgui("after 0 {::pddp::srvUse %s}\n", x->x_dirsym->s_name);
+ return (x);
+}
+
+void pddplink_setup(void)
+{
+ t_symbol *dirsym;
+ post("this is pddplink %s, %s %s build...",
+ PDDP_VERSION, loud_ordinal(PDDP_BUILD), PDDP_RELEASE);
+ pddplink_class = class_new(gensym("pddplink"),
+ (t_newmethod)pddplink_new,
+ (t_method)pddplink_free,
+ sizeof(t_pddplink),
+ CLASS_NOINLET | CLASS_PATCHABLE,
+ A_DEFSYM, A_DEFSYM, 0);
+ class_addanything(pddplink_class, pddplink_anything);
+ class_addmethod(pddplink_class, (t_method)pddplink_click,
+ gensym("click"),
+ A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+#ifdef PDDPLINK_DEBUG
+ class_addmethod(pddplink_class, (t_method)pddplink_debug,
+ gensym("debug"), 0);
+#endif
+ dirsym = pddplink_class->c_externdir; /* FIXME */
+ sys_vgui("namespace eval ::pddp {variable theDir [pwd]}; cd %s\n",
+ dirsym->s_name);
+ sys_gui("after 0 {source pddpboot.tcl}\n");
+}
diff --git a/pddp/pddpserver.tcl b/pddp/pddpserver.tcl
new file mode 100644
index 0000000..fe17948
--- /dev/null
+++ b/pddp/pddpserver.tcl
@@ -0,0 +1,490 @@
+# pddpserver.tcl
+
+# Synopsis
+# not to be run by itself (see pddpboot.tcl)
+
+# based on:
+
+# Simple Sample httpd/1.[01] server
+# Stephen Uhler (c) 1996-1997 Sun Microsystems
+
+# http://cvs.sourceforge.net/viewcvs.py/tclhttpd/tclhttpd/bin/mini/mini1.1.tcl
+
+# modified by krzYszcz (2005):
+# putting per-server data and all commands in a namespace "::pddp"
+# supporting sourcing from within Pd, through the "pddpboot.tcl" wrapper
+# inserting the .pd handler
+# lots of other changes, too many to list here (run "diff" if curious...)
+
+if {![namespace exists ::pddp]} {
+ puts stderr "Error: invalid invocation of pddpserver (boot pddp first)"
+ puts stderr "exiting..."
+ exit 1
+}
+
+if {$::pddp::testrun} { ;# true if sourced from standalone "pddpboot.tcl"
+ puts stderr "Loading pddpserver, test run..."
+ proc bgerror {msg} {
+ global errorInfo
+ puts stderr "bgerror: $msg\n$errorInfo"
+ }
+} else {
+ puts stderr "Loading pddpserver"
+ catch {console show}
+}
+
+namespace eval ::pddp {
+ variable thePort 8080
+ variable theState
+ variable theMimeTypes
+ variable theErrors
+ variable theErrorFormat
+
+ # "theState" contains the server state:
+ # root: the root of the document directory
+ # default: default document name
+ # listen: the main listening socket id
+ # naccepts: a count of accepted connections so far
+ # maxtime: the max time (msec) allowed to complete an http request
+ # maxused: the max # of requests for a socket
+ array set theState {
+ root ""
+ default index.html
+ listen ""
+ naccepts 0
+ nrequests 0
+ nerrors 0
+ maxtime 600000
+ maxused 25
+ bufsize 32768
+ }
+
+ set theState(root) $env(HOME)
+
+ array set theMimeTypes {
+ {} text/plain
+ .txt text/plain
+ .html text/html
+ .gif image/gif
+ .jpg image/jpeg
+ .pd text/html
+ }
+
+ # HTTP/1.[01] error codes (the ones we use)
+ array set theErrors {
+ 204 {No Content}
+ 400 {Bad Request}
+ 404 {Not Found}
+ 405 {Method Not Allowed}
+ 408 {Request Timeout}
+ 411 {Length Required}
+ 419 {Expectation Failed}
+ 500 {Internal Server Error}
+ 503 {Service Unavailable}
+ 504 {Service Temporarily Unavailable}
+ 505 {HTTP Version Not Supported}
+ }
+
+ # Generic error response
+ set theErrorFormat {
+ <title>Error: %1$s</title>
+ Got the error: <b>%2$s</b><br>
+ while trying to obtain <b>%3$s</b>
+ }
+}
+
+proc ::pddp::srvUse {{root {}} {port 8080}} {
+ variable theState
+ if {[string length $theState(listen)]} {
+ if {[string length $root] && ![string equal $root $theState(root)]} {
+ srvLog $theState(listen) Warning "Redirection attempt for $root"
+ }
+ } else {
+ srvStart $root $port
+ }
+}
+
+# Start the server by listening for connections on the desired port.
+
+proc ::pddp::srvStart {{root {}} {port 8080}} {
+ variable thePort
+ variable theState
+
+ puts stderr "Starting pddp server on [info hostname]"
+ if {[string length $root]} {
+ set theState(root) $root
+ }
+ # we do not handle multiple pddpservers, LATER rethink
+ srvStop
+ array set theState [list naccepts 0 nrequests 0 nerrors 0]
+
+ for { set thePort $port } {$thePort < 32767 } {incr thePort } {
+ if {[catch {set theState(listen) \
+ [socket -server ::pddp::srvAccept $thePort]} res]} {
+ if {$thePort == 0} {
+ # FIXME this is a critical error
+ set thePort 8080
+ }
+ } else { break }
+ }
+ if {$thePort == 32767} {
+ srvLog none Error "Could not find port available for listening"
+ } else {
+ if {$thePort == 0} {
+ set thePort [lindex [fconfigure $theState(listen) -sockname] 2]
+ }
+ srvLog $theState(listen) Port $thePort
+ srvLog $theState(listen) Root directory \"$root\"
+ }
+ after 120 update ;# FIXME might be needed on windows they say, test there
+ return $thePort
+}
+
+proc ::pddp::srvStop {} {
+ variable thePort
+ variable theState
+ if {[string length $theState(listen)]} {
+ if {[catch {close $theState(listen)} res]} {
+ srvLog $theState(listen) Warning [list $res while closing socket]
+ } else {
+ srvLog $theState(listen) Closed.
+ }
+ set theState(listen) ""
+ update
+ }
+}
+
+# Accept a new connection from the server and set up a handler
+# to read the request from the client.
+
+proc ::pddp::srvAccept {sock ipaddr port} {
+ variable theState
+ variable theSockData$sock
+ # reject remote requests, LATER revisit
+ if {[string equal $ipaddr "127.0.0.1"]} {
+ incr theState(naccepts)
+ srvReset $sock $theState(maxused)
+ srvLog $sock Connect $ipaddr $port
+ } else {
+ srvLog $sock Warning "rejecting remote connection request from $ipaddr"
+ srvSockDone $sock 1
+ }
+}
+
+# Initialize or reset the socket state
+
+proc ::pddp::srvReset {sock nlft} {
+ variable theState
+ upvar 0 ::pddp::theSockData$sock sockData
+ array set sockData [list state start linemode 1 version 0 nleft $nlft]
+ set sockData(cancel) \
+ [after $theState(maxtime) [list srvTimeout $sock]]
+ fconfigure $sock -blocking 0 -buffersize $theState(bufsize) \
+ -translation {auto crlf}
+ fileevent $sock readable [list ::pddp::srvRead $sock]
+}
+
+# Read data from a client request
+# 1) read the request line
+# 2) read the mime headers
+# 3) read the additional data (if post && content-length not satisfied)
+
+proc ::pddp::srvRead {sock} {
+ variable theState
+ upvar 0 ::pddp::theSockData$sock sockData
+
+ # Use line mode to read the request and the mime headers
+
+ if {$sockData(linemode)} {
+ set readCount [gets $sock line]
+ set state [string compare $readCount 0],$sockData(state)
+ switch -glob -- $state {
+ 1,start {
+ if {[regexp {(HEAD|POST|GET) ([^?]+)\??([^ ]*) HTTP/1.([01])} \
+ $line x sockData(proto) sockData(url) \
+ sockData(query) sockData(version)]} {
+ set sockData(state) mime
+ incr theState(nrequests)
+ srvLog $sock Request $sockData(nleft) $line
+ } else {
+ srvError $sock 400 $line
+ }
+ }
+ 0,start {
+ srvLog $sock Warning "Initial blank line fetching request"
+ }
+ 1,mime {
+ if {[regexp {([^:]+):[ ]*(.*)} $line {} key value]} {
+ set key [string tolower $key]
+ set sockData(key) $key
+ if {[info exists sockData(mime,$key)]} {
+ append sockData(mime,$key) ", $value"
+ } else {
+ set sockData(mime,$key) $value
+ }
+ } elseif {[regexp {^[ ]+(.+)} $line {} value] && \
+ [info exists sockData(key)]} {
+ append sockData(mime,$sockData($key)) " " $value
+ } else {
+ srvError $sock 400 $line
+ }
+ }
+ 0,mime {
+ if {$sockData(proto) == "POST" && \
+ [info exists sockData(mime,content-length)]} {
+ set sockData(linemode) 0
+ set sockData(count) $sockData(mime,content-length)
+ if {$sockData(version) && \
+ [info exists sockData(mime,expect)]} {
+ if {$sockData(mime,expect) == "100-continue"} {
+ puts $sock "100 Continue HTTP/1.1\n"
+ flush $sock
+ } else {
+ srvError $sock 419 $sockData(mime,expect)
+ }
+ }
+ fconfigure $sock -translation {binary crlf}
+ } elseif {$sockData(proto) != "POST"} {
+ srvRespond $sock
+ } else {
+ srvError $sock 411 "Confusing mime headers"
+ }
+ }
+ -1,* {
+ if {[eof $sock]} {
+ srvLog $sock Error "Broken connection fetching request"
+ srvSockDone $sock 1
+ } else {
+ puts stderr "Partial read, retrying"
+ }
+ }
+ default {
+ srvError $sock 404 "Invalid http state: $state,[eof $sock]"
+ }
+ }
+
+ # Use counted mode to get the post data
+
+ } elseif {![eof $sock]} {
+ append sockData(postdata) [read $sock $sockData(count)]
+ set sockData(count) [expr {$sockData(mime,content-length) - \
+ [string length $sockData(postdata)]}]
+ if {$sockData(count) == 0} {
+ srvRespond $sock
+ }
+ } else {
+ srvLog $sock Error "Broken connection reading POST data"
+ srvSockDone $sock 1
+ }
+}
+
+# Done with the socket, either close it, or set up for next fetch
+# sock: The socket I'm done with
+# doclose: If true, close the socket, otherwise set up for reuse
+
+proc ::pddp::srvSockDone {sock doclose} {
+ variable theState
+ upvar 0 ::pddp::theSockData$sock sockData
+
+ after cancel $sockData(cancel)
+ set nleft [incr sockData(nleft) -1]
+ unset sockData
+ if {$doclose} {
+ close $sock
+ } else {
+ srvReset $sock $nleft
+ }
+ return ""
+}
+
+# A timeout happened
+
+proc ::pddp::srvTimeout {sock} {
+ srvError $sock 408
+}
+
+# FIXME test if "path" has its patch window already open...
+proc ::pddp::srvPdHandler {sock path} {
+ set dir [file dirname $path]
+ set tail [file tail $path]
+ if {[catch {pd [concat pd open $tail $dir \;]}]} {
+ srvError $sock 504
+ } else {
+ srvError $sock 204
+ # FIXME raise; focus (test on windows)
+ }
+}
+
+# Handle file system queries. This is a place holder for a more
+# generic dispatch mechanism.
+
+proc ::pddp::srvRespond {sock} {
+ variable theState
+ variable theUrlCache
+ upvar 0 ::pddp::theSockData$sock sockData
+
+ regsub {(^http://[^/]+)?} $sockData(url) {} url
+ if {[info exists theUrlCache($url)]} {
+ set mypath $theUrlCache($url)
+ } else {
+ set mypath [srvUrl2File $theState(root) $url]
+ if {[file isdirectory $mypath]} {
+ append mypath / $theState(default)
+ }
+ set theUrlCache($url) $mypath
+ }
+ if {[string length $mypath] == 0} {
+ srvError $sock 400
+ } elseif {![file readable $mypath]} {
+ if {[string equal [file tail $mypath] "favicon.ico"]} {
+ srvError $sock 204 ;# FIXME design something
+ } else {
+ srvError $sock 404 $mypath
+ }
+ } else {
+ set ext [file extension $mypath]
+
+ if {[string equal $ext ".pd"]} {
+ srvPdHandler $sock $mypath
+ return
+ }
+
+ puts $sock "HTTP/1.$sockData(version) 200 Data follows"
+ puts $sock "Date: [srvGetDate [clock seconds]]"
+ puts $sock "Last-Modified: [srvGetDate [file mtime $mypath]]"
+ puts $sock "Content-Type: [srvContentType $ext]"
+ puts $sock "Content-Length: [file size $mypath]"
+
+ ## Should also close socket if recvd connection close header
+ set doclose [expr {$sockData(nleft) == 0}]
+
+ if {$doclose} {
+ puts $sock "Connection close:"
+ } elseif {$sockData(version) == 0 && \
+ [info exists sockData(mime,connection)]} {
+ if {$sockData(mime,connection) == "Keep-Alive"} {
+ set doclose 0
+ puts $sock "Connection: Keep-Alive"
+ }
+ }
+ puts $sock ""
+ flush $sock
+
+ if {$sockData(proto) != "HEAD"} {
+ set in [open $mypath]
+ fconfigure $sock -translation binary
+ fconfigure $in -translation binary
+ fcopy $in $sock -command \
+ [list ::pddp::srvCopyDone $in $sock $doclose]
+ } else {
+ srvSockDone $sock $doclose
+ }
+ }
+}
+
+# Callback when file is done being output to client
+# in: The fd for the file being copied
+# sock: The client socket
+# doclose: close the socket if true
+# bytes: The # of bytes copied
+# error: The error message (if any)
+
+proc ::pddp::srvCopyDone {in sock doclose bytes {error {}}} {
+ close $in
+ srvLog $sock Done $bytes bytes
+ srvSockDone $sock $doclose
+}
+
+# Convert the file suffix into a mime type.
+
+proc ::pddp::srvContentType {ext} {
+ variable theMimeTypes
+ set type text/plain
+ catch {set type $theMimeTypes($ext)}
+ return $type
+}
+
+# Respond with an error reply
+# sock: The socket handle to the client
+# code: The httpd error code
+# args: Additional information for error logging
+
+proc ::pddp::srvError {sock code args} {
+ variable theState
+ variable theErrors
+ variable theErrorFormat
+ upvar 0 ::pddp::theSockData$sock sockData
+
+ append sockData(url) ""
+ incr theState(nerrors)
+ set message [format $theErrorFormat $code $theErrors($code) $sockData(url)]
+ append head "HTTP/1.$sockData(version) $code $theErrors($code)" \n
+ append head "Date: [srvGetDate [clock seconds]]" \n
+ append head "Connection: close" \n
+ append head "Content-Length: [string length $message]" \n
+
+ # Because there is an error condition, the socket may be "dead"
+
+ catch {
+ fconfigure $sock -translation crlf
+ puts -nonewline $sock $head\n$message
+ flush $sock
+ } reason
+ srvSockDone $sock 1
+ if {$code < 300} {set status Status} else {set status Error}
+ srvLog $sock $status $code $theErrors($code) $args $reason
+}
+
+# Generate a date string in HTTP format.
+
+proc ::pddp::srvGetDate {seconds} {
+ return [clock format $seconds -format {%a, %d %b %Y %T %Z}]
+}
+
+# Log an Httpd transaction.
+# This should be replaced as needed.
+
+proc ::pddp::srvLog {sock args} {
+ puts stderr "pddp log ($sock): $args"
+}
+
+# Convert a url into a pathname. (UNIX version only)
+# This is probably not right, and belongs somewhere else.
+# - Remove leading http://... if any
+# - Collapse all /./ and /../ constructs
+# - expand %xx sequences -> disallow "/"'s and "."'s due to expansions
+
+proc ::pddp::srvUrl2File {root url} {
+ regsub -all {//+} $url / url ;# collapse multiple /'s
+ while {[regsub -all {/\./} $url / url]} {} ;# collapse /./
+ while {[regsub -all {/\.\.(/|$)} $url /\x81\\1 url]} {} ;# mark /../
+ while {[regsub "/\[^/\x81]+/\x81/" $url / url]} {} ;# collapse /../
+ if {![regexp "\x81|%2\[eEfF]" $url]} { ;# invalid /../, / or . ?
+ return $root[srvCgiMap $url]
+ } else {
+ return ""
+ }
+}
+
+# Decode url-encoded strings.
+
+proc ::pddp::srvCgiMap {data} {
+ regsub -all {([][$\\])} $data {\\\1} data
+ regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $data {[format %c 0x\1]} data
+ return [subst $data]
+}
+
+if {$::pddp::testrun} { ;# true if tested as a standalone script
+ if {$argc > 1} {
+ set root [lindex $argv 1]
+ set port [lindex $argv 2]
+ if {![string is integer -strict $port]} {
+ set port 8080
+ }
+ } else {
+ set root $env(HOME)
+ set port 8080
+ }
+ ::pddp::srvStart $root $port
+ vwait forever
+}
diff --git a/test/pddp/pddp.css b/test/pddp/pddp.css
new file mode 100644
index 0000000..40042d1
--- /dev/null
+++ b/test/pddp/pddp.css
@@ -0,0 +1,18 @@
+body {
+ color: brown ;
+ background: gray url(test.bg.jpg) ;
+ margin-top: 10 ;
+ font-family: Helvetica, sans-serif ;
+ font-size: larger ;
+}
+
+pre.programlisting {
+ display: table ;
+ background-color: #EEEEEE ;
+ padding: 2pt ;
+ border-style: solid ;
+ border-width: 1pt ;
+ border-color: #000000 ;
+ border-spacing: 3pt ;
+ margin: 3pt ;
+}
diff --git a/test/pddp/pddplink-test-01.html b/test/pddp/pddplink-test-01.html
new file mode 100644
index 0000000..b73ea54
--- /dev/null
+++ b/test/pddp/pddplink-test-01.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>first simple test</title><link rel="stylesheet" href="pddp.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.66.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2447708"></a>first simple test</h2></div></div><hr></div><p>test patch is here: <a href="pddplink-test-01.pd" target="_top">pddplink-test-01.pd</a></p><p>The above link works if you opened this page from Pd,
+ for example, by clicking on an object
+ </p><pre class="programlisting"><span><b class="command">pddplink</b></span> pddplink-test-01.html</pre><p>
+ </p><p>Pd links should also work in all pages opened through any other,
+ initiating, Pd-opened page.</p><p>Another simple test page is here: <a href="pddplink-test-02.html" target="_top">pddplink-test-02.html</a></p></div></body></html>
diff --git a/test/pddp/pddplink-test-01.pd b/test/pddp/pddplink-test-01.pd
new file mode 100644
index 0000000..f5f1403
--- /dev/null
+++ b/test/pddp/pddplink-test-01.pd
@@ -0,0 +1,8 @@
+#N canvas 232 221 450 300 12;
+#X obj 61 83 pddplink pddplink-test-01.html;
+#X text 21 12 first entry;
+#X text 59 47 linking to a local html page:;
+#X text 58 130 linking to a remote html page:;
+#X obj 60 166 pddplink http://puredata.info;
+#X obj 59 254 pddplink pddplink-test-02.pd;
+#X text 57 218 linking to another local patch:;
diff --git a/test/pddp/pddplink-test-01.xml b/test/pddp/pddplink-test-01.xml
new file mode 100644
index 0000000..0282ea6
--- /dev/null
+++ b/test/pddp/pddplink-test-01.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<sect1>
+ <title>first simple test</title>
+
+ <para>test patch is here: <ulink url="pddplink-test-01.pd"/></para>
+
+ <para>The above link works if you opened this page from Pd,
+ for example, by clicking on an object
+ <programlisting><command>pddplink</command> pddplink-test-01.html</programlisting>
+ </para>
+
+ <para>Pd links should also work in all pages opened through any other,
+ initiating, Pd-opened page.</para>
+
+ <para>Another simple test page is here: <ulink url="pddplink-test-02.html"/></para>
+</sect1>
diff --git a/test/pddp/pddplink-test-02.html b/test/pddp/pddplink-test-02.html
new file mode 100644
index 0000000..aed49db
--- /dev/null
+++ b/test/pddp/pddplink-test-02.html
@@ -0,0 +1,5 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>second simple test</title><link rel="stylesheet" href="pddp.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.66.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id2447708"></a>second simple test</h2></div></div><hr></div><p>test patch is here: <a href="pddplink-test-02.pd" target="_top">pddplink-test-02.pd</a></p><p>The above link works if you opened this page from Pd,
+ for example, by clicking on an object
+ </p><pre class="programlisting"><span><b class="command">pddplink</b></span> pddplink-test-02.html</pre><p>
+ </p><p>Pd links should also work in all pages opened through any other,
+ initiating, Pd-opened page.</p><p>Another simple test page is here: <a href="pddplink-test-01.html" target="_top">pddplink-test-01.html</a></p></div></body></html>
diff --git a/test/pddp/pddplink-test-02.pd b/test/pddp/pddplink-test-02.pd
new file mode 100644
index 0000000..eb67411
--- /dev/null
+++ b/test/pddp/pddplink-test-02.pd
@@ -0,0 +1,8 @@
+#N canvas 332 321 450 300 12;
+#X obj 61 83 pddplink pddplink-test-02.html;
+#X text 21 12 second entry;
+#X text 59 47 linking to a local html page:;
+#X text 58 130 linking to a remote html page:;
+#X obj 60 166 pddplink http://puredata.info;
+#X obj 59 254 pddplink pddplink-test-01.pd;
+#X text 57 218 linking to another local patch:;
diff --git a/test/pddp/pddplink-test-02.xml b/test/pddp/pddplink-test-02.xml
new file mode 100644
index 0000000..349f95e
--- /dev/null
+++ b/test/pddp/pddplink-test-02.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<sect1>
+ <title>second simple test</title>
+
+ <para>test patch is here: <ulink url="pddplink-test-02.pd"/></para>
+
+ <para>The above link works if you opened this page from Pd,
+ for example, by clicking on an object
+ <programlisting><command>pddplink</command> pddplink-test-02.html</programlisting>
+ </para>
+
+ <para>Pd links should also work in all pages opened through any other,
+ initiating, Pd-opened page.</para>
+
+ <para>Another simple test page is here: <ulink url="pddplink-test-01.html"/></para>
+</sect1>
diff --git a/test/pddp/test.bg.jpg b/test/pddp/test.bg.jpg
new file mode 100644
index 0000000..8224bbc
--- /dev/null
+++ b/test/pddp/test.bg.jpg
Binary files differ
diff --git a/test/pddp/toonepage b/test/pddp/toonepage
new file mode 100755
index 0000000..f59273a
--- /dev/null
+++ b/test/pddp/toonepage
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+usage () {
+ cat << EOF
+usage: toonepage <pddpsource>.xml
+EOF
+}
+
+[ "$#" == 0 ] && { usage; exit 1; }
+
+SOURCE_NAME="$(basename $1)"
+SOURCE_STUB="$(basename $SOURCE_NAME .xml)"
+
+[ $SOURCE_STUB == $SOURCE_NAME ] && { usage; exit 1; }
+
+xmllint >/dev/null --xinclude --postvalid $1
+xsltproc --nonet --xinclude \
+ --stringparam html.stylesheet pddp.css \
+ -o "$SOURCE_STUB.html" \
+ /usr/share/xml/docbook/stylesheet/nwalsh/html/docbook.xsl \
+ $1
diff --git a/test/pddp/topdf b/test/pddp/topdf
new file mode 100755
index 0000000..adf4b43
--- /dev/null
+++ b/test/pddp/topdf
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+usage () {
+ cat << EOF
+usage: topdf <pddpsource>.xml
+EOF
+}
+
+[ "$#" == 0 ] && { usage; exit 1; }
+
+SOURCE_NAME="$(basename $1)"
+SOURCE_STUB="$(basename $SOURCE_NAME .xml)"
+
+[ $SOURCE_STUB == $SOURCE_NAME ] && { usage; exit 1; }
+
+xmllint >/dev/null --xinclude --postvalid $1
+xsltproc --nonet --xinclude \
+ -o "$SOURCE_STUB.fo" \
+ /usr/share/xml/docbook/stylesheet/nwalsh/fo/docbook.xsl \
+ $1
+
+# FIXME need to run this twice, it should be check-wrapped too
+pdfxmltex "$SOURCE_STUB.fo"