From 2f98cf610081a6e3c4a4aadf4411dcc89b756db2 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 10 May 2005 20:30:47 +0000 Subject: toxy alpha17 and pddp alpha1 (see notes.txt for toxy, pddp and shared) svn path=/trunk/externals/miXed/; revision=2941 --- Makefile | 2 +- Makefile.common | 3 +- Makefile.dirs | 2 + ViCious/pddp/makefile | 53 +++++ ViCious/pddp/objects | 3 + ViCious/pddp/snapfiles | 10 + ViCious/toxy/objects | 1 + ViCious/toxy/snapfiles | 1 + cyclone/hammer/testmess.c | 2 +- cyclone/notes.txt | 2 + pddp/Makefile | 10 + pddp/Makefile.objects | 3 + pddp/Makefile.sources | 3 + pddp/build_counter | 7 + pddp/notes.txt | 10 + pddp/pddp-all.exclude | 8 + pddp/pddp-help.include | 0 pddp/pddp-shared.include | 5 + pddp/pddp-test.exclude | 5 + pddp/pddp-vicious.exclude | 3 + pddp/pddpboot.tcl | 32 +++ pddp/pddpclient.tcl | 82 +++++++ pddp/pddplink.c | 136 +++++++++++ pddp/pddpserver.tcl | 490 ++++++++++++++++++++++++++++++++++++++++ test/pddp/pddp.css | 18 ++ test/pddp/pddplink-test-01.html | 5 + test/pddp/pddplink-test-01.pd | 8 + test/pddp/pddplink-test-01.xml | 19 ++ test/pddp/pddplink-test-02.html | 5 + test/pddp/pddplink-test-02.pd | 8 + test/pddp/pddplink-test-02.xml | 19 ++ test/pddp/test.bg.jpg | Bin 0 -> 5491 bytes test/pddp/toonepage | 21 ++ test/pddp/topdf | 23 ++ 34 files changed, 996 insertions(+), 3 deletions(-) create mode 100644 ViCious/pddp/makefile create mode 100644 ViCious/pddp/objects create mode 100644 ViCious/pddp/snapfiles create mode 100644 pddp/Makefile create mode 100644 pddp/Makefile.objects create mode 100644 pddp/Makefile.sources create mode 100644 pddp/build_counter create mode 100644 pddp/notes.txt create mode 100644 pddp/pddp-all.exclude create mode 100644 pddp/pddp-help.include create mode 100644 pddp/pddp-shared.include create mode 100644 pddp/pddp-test.exclude create mode 100644 pddp/pddp-vicious.exclude create mode 100755 pddp/pddpboot.tcl create mode 100644 pddp/pddpclient.tcl create mode 100644 pddp/pddplink.c create mode 100644 pddp/pddpserver.tcl create mode 100644 test/pddp/pddp.css create mode 100644 test/pddp/pddplink-test-01.html create mode 100644 test/pddp/pddplink-test-01.pd create mode 100644 test/pddp/pddplink-test-01.xml create mode 100644 test/pddp/pddplink-test-02.html create mode 100644 test/pddp/pddplink-test-02.pd create mode 100644 test/pddp/pddplink-test-02.xml create mode 100644 test/pddp/test.bg.jpg create mode 100755 test/pddp/toonepage create mode 100755 test/pddp/topdf 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 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 +#include +#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 { + Error: %1$s + Got the error: %2$s
+ while trying to obtain %3$s + } +} + +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 @@ +first simple test

first simple test


test patch is here: pddplink-test-01.pd

The above link works if you opened this page from Pd, + for example, by clicking on an object +

pddplink pddplink-test-01.html

+

Pd links should also work in all pages opened through any other, + initiating, Pd-opened page.

Another simple test page is here: pddplink-test-02.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 @@ + + + + + first simple test + + test patch is here: + + The above link works if you opened this page from Pd, + for example, by clicking on an object + pddplink pddplink-test-01.html + + + Pd links should also work in all pages opened through any other, + initiating, Pd-opened page. + + Another simple test page is here: + 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 @@ +second simple test

second simple test


test patch is here: pddplink-test-02.pd

The above link works if you opened this page from Pd, + for example, by clicking on an object +

pddplink pddplink-test-02.html

+

Pd links should also work in all pages opened through any other, + initiating, Pd-opened page.

Another simple test page is here: pddplink-test-01.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 @@ + + + + + second simple test + + test patch is here: + + The above link works if you opened this page from Pd, + for example, by clicking on an object + pddplink pddplink-test-02.html + + + Pd links should also work in all pages opened through any other, + initiating, Pd-opened page. + + Another simple test page is here: + diff --git a/test/pddp/test.bg.jpg b/test/pddp/test.bg.jpg new file mode 100644 index 0000000..8224bbc Binary files /dev/null and b/test/pddp/test.bg.jpg 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 .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 .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" -- cgit v1.2.1