tcl-rivet-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mxman...@apache.org
Subject svn commit: r1076029 - in /tcl/rivet/trunk: ./ ChangeLog doc/xml/commands.xml doc/xml/directives.xml src/apache-2/mod_rivet.c src/apache-2/mod_rivet.h src/apache-2/rivetCore.c
Date Tue, 01 Mar 2011 22:04:11 GMT
Author: mxmanghi
Date: Tue Mar  1 22:04:11 2011
New Revision: 1076029

URL: http://svn.apache.org/viewvc?rev=1076029&view=rev
Log:
committing new code reintegrated into trunk from branches/neh (New exception handling)


Modified:
    tcl/rivet/trunk/   (props changed)
    tcl/rivet/trunk/ChangeLog
    tcl/rivet/trunk/doc/xml/commands.xml
    tcl/rivet/trunk/doc/xml/directives.xml
    tcl/rivet/trunk/src/apache-2/mod_rivet.c
    tcl/rivet/trunk/src/apache-2/mod_rivet.h
    tcl/rivet/trunk/src/apache-2/rivetCore.c

Propchange: tcl/rivet/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Mar  1 22:04:11 2011
@@ -1,2 +1,3 @@
 /tcl/rivet/branches/2_0:939332-1027850
 /tcl/rivet/branches/master-interp:1062190-1065801
+/tcl/rivet/branches/neh:1069501-1076014

Modified: tcl/rivet/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/ChangeLog?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/ChangeLog (original)
+++ tcl/rivet/trunk/ChangeLog Tue Mar  1 22:04:11 2011
@@ -1,6 +1,17 @@
+2011-03-01 Massimo Manghi <mxmanghi@apache.org>
+    * src/apache-2/rivetCode.c: 'abort_code' command is now created through the RIVET_CMD_OBJ
macro
+
 2011-02-14 Karl Lehenbauer <karl@apache.org>
-    * src/apache-2/mod_rivet.c: Only create root interpreter once, not twice.  In Rivet_CopyConfig
cache_size and cache_free were getting copied twice.  Only once now.
-    * src/apache-2/rivetCore.c: Remove unused command var from Rivet_Upload.  Remove unneeded
loglevel var from Rivet_LogErrorCmd.
+    * src/apache-2/mod_rivet.c: Only create root interpreter once, not twice.  
+    In Rivet_CopyConfig cache_size and cache_free were getting copied twice.  
+    Only once now.
+    * src/apache-2/rivetCore.c: Remove unused command var from Rivet_Upload.
+    Remove unneeded loglevel var from Rivet_LogErrorCmd.
+
+2011-02-11 Massimo Manghi <mxmanghi@apache.org>
+    * src/apache-2/mod_rivet.[c|h]: new conf scripts rivet_abort_script and rivet_force_script.
rivet_abort_script
+    is run when an abort_page command is called in the page content generation
+    * src/apache-2/rivetCode.c: add new command abort_code that returns the code passed to
abort_page
 
 2011-01-31 Massimo Manghi <mxmanghi@apache.org>
     * configure.ac: default value for directive SeparateVirtualInterps changed to 'yes'.

Modified: tcl/rivet/trunk/doc/xml/commands.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/xml/commands.xml?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/xml/commands.xml (original)
+++ tcl/rivet/trunk/doc/xml/commands.xml Tue Mar  1 22:04:11 2011
@@ -749,42 +749,42 @@
 
     <refentry id="incr0">
       <refnamediv>
-	<refname>incr0</refname>
-	<refpurpose>increment a variable or set it to 1 if nonexistent.</refpurpose>
+			<refname>incr0</refname>
+			<refpurpose>increment a variable or set it to 1 if nonexistent.</refpurpose>
       </refnamediv>
 
       <refsynopsisdiv>
-	<cmdsynopsis>
-	  <command>incr0</command>
-	  <arg><replaceable>varname</replaceable></arg>
-	  <arg><replaceable>num</replaceable></arg>
-	</cmdsynopsis>
+			<cmdsynopsis>
+			  <command>incr0</command>
+			  <arg><replaceable>varname</replaceable></arg>
+			  <arg><replaceable>num</replaceable></arg>
+			</cmdsynopsis>
       </refsynopsisdiv>
 
       <refsect1>
-	<title>Description</title>
-	<para>
-	  Increment a variable
-	  <option><replaceable>varname</replaceable></option> by
-	  <option><replaceable>num</replaceable></option>.  If the
-	  variable doesn't exist, create it instead of returning an
-	  error.
-	</para>
+			<title>Description</title>
+			<para>
+			  Increment a variable
+			  <option><replaceable>varname</replaceable></option> by
+			  <option><replaceable>num</replaceable></option>.  If the
+			  variable doesn't exist, create it instead of returning an
+			  error.
+			</para>
       </refsect1>
     </refentry>
 
     <refentry id="parray">
       <refnamediv>
-	<refname>parray</refname>
-	<refpurpose>Tcl's <command>parray</command> with html formatting.</refpurpose>
+			<refname>parray</refname>
+			<refpurpose>Tcl's <command>parray</command> with html formatting.</refpurpose>
       </refnamediv>
 
       <refsynopsisdiv>
-	<cmdsynopsis>
-	  <command>parray</command>
-	  <arg><replaceable>arrayName</replaceable></arg>
-	  <arg><replaceable><optional>pattern</optional></replaceable></arg>
-	</cmdsynopsis>
+			<cmdsynopsis>
+	  			<command>parray</command>
+	  			<arg><replaceable>arrayName</replaceable></arg>
+	  			<arg><replaceable><optional>pattern</optional></replaceable></arg>
+				</cmdsynopsis>
       </refsynopsisdiv>
 
       <refsect1>
@@ -801,79 +801,129 @@
 
     <refentry id="abort_page">
       <refnamediv>
-	<refname>abort_page</refname>
-	<refpurpose>Stops outputing data to web page, similar in
-	  purpose to PHP's <command>die</command> command.</refpurpose>
+			<refname>abort_page</refname>
+			<refpurpose>
+				Stops outputing data to web page, similar in
+			  	purpose to PHP's <command>die</command> command.
+			</refpurpose>
       </refnamediv>
 
       <refsynopsisdiv>
-	<cmdsynopsis>
-	  <command>abort_page</command>
-	</cmdsynopsis>
+			<cmdsynopsis>
+			  	<command>abort_page</command>
+			  	<group choice="req">
+					<arg><replaceable>abort code</replaceable></arg>
+					<arg><replaceable>-aborting</replaceable></arg>
+				</group>
+			</cmdsynopsis>
       </refsynopsisdiv>
 
       <refsect1>
-	<title>Description</title> <para>This command flushes the
-	output buffer and stops the Tcl script from sending any more
-	data to the client.  A normal Tcl script might use the
-	<command>exit</command> command, but that cannot be used in
-	Rivet without actually exiting the apache child
-	process!</para>
+			<title>Description</title> 
+			<para>
+				This command flushes the output buffer and stops the Tcl 
+				script from sending any more data to the client.
+				A normal Tcl script might use the
+				<command>exit</command> command, but that cannot be used in
+				Rivet without actually exiting the apache child
+				process!
+				<command>abort_page</command> triggers
+				the execution of an optional AbortScript that has to be
+				specified in the configuration. The value of the
+				argument <arg>abort code</arg> can be retrieved with the 
+				<command>abort_code</command> command during the
+				execution of AbortScript or AfterEveryScript, allowing 
+				the script to take appropriate actions in order to deal
+				with the cause of the abort. 
+			</para>
+			<para>
+				When passed the argument <option>-aborting</option> the
+				command returns 1 if <option>abort_page</option>
+				had been called earlier in the request processing, thus
+				providing a tool for code in AfterEveryScript to tell
+				if the an abort condition took place.
+			</para>
       </refsect1>
-    </refentry>
+   </refentry>
 
-    <refentry id="no_body">
+	<refentry id="abort_code">
+		<refnamediv>
+			<refname>abort_code</refname>
+			<refpurpose>
+				Returns the code passed to <command>abort_page</command>
+				earlier during the request processing
+			</refpurpose>
+		</refnamediv>
+		<refsynopsisdiv>
+			<cmdsynopsis>
+			  <command>abort_page</command>
+			  <arg><replaceable>abort code</replaceable></arg>
+			</cmdsynopsis>
+      </refsynopsisdiv>
+      <refsect1>
+			<title>Description</title> 
+			<para>
+				Usage of this command is meaningful only in code that runs as
+				AbortScript or AfterEveryScript. 
+				<command>abort_code</command> returns the value of the optional 
+				parameter passed to <command>abort_page</command> earlier in
+				the same request processing.
+			</para>
+      </refsect1>
+	</refentry>
+	
+   <refentry id="no_body">
       <refnamediv>
-	<refname>no_body</refname>
-	<refpurpose>Prevents Rivet from sending any content.</refpurpose>
+			<refname>no_body</refname>
+			<refpurpose>Prevents Rivet from sending any content.</refpurpose>
       </refnamediv>
 
       <refsynopsisdiv>
-	<cmdsynopsis>
-	  <command>no_body</command>
-	</cmdsynopsis>
+			<cmdsynopsis>
+			  <command>no_body</command>
+			</cmdsynopsis>
       </refsynopsisdiv>
 
       <refsect1>
-	<title>Description</title>
-	<para>
-	  This command is useful for situations where it is necessary
-	  to only return HTTP headers and no actual content.  For
-	  instance, when returning a 304 redirect.
-	</para>
-      </refsect1>
-    </refentry>
+			<title>Description</title>
+			<para>
+			  This command is useful for situations where it is necessary
+			  to only return HTTP headers and no actual content.  For
+			  instance, when returning a 304 redirect.
+			</para>
+   	</refsect1>
+	</refentry>
 
-    <refentry id="escape_string">
+   <refentry id="escape_string">
       <refnamediv>
 			<refname>escape_string</refname>
 			<refpurpose>convert a string into escaped characters.</refpurpose>
       </refnamediv>
 
       <refsynopsisdiv>
-	<cmdsynopsis>
-	  <command>escape_string</command>
-	  <arg>string</arg>
-	</cmdsynopsis>
+			<cmdsynopsis>
+			  <command>escape_string</command>
+			  <arg>string</arg>
+			</cmdsynopsis>
       </refsynopsisdiv>
 
       <refsect1>
-	<title>Description</title>
-	<para>
-	    Scans through each character in the specified string looking
-	    for special characters, escaping them as needed, mapping
-	    special characters to a quoted hexadecimal equivalent,
-	    returning the result.
-	</para>
-	<para>
-	    This is useful for quoting strings that are going to be
-	    part of a URL.
-	</para>
-	<note> 
-	    You must require the Rivet package in order to gain access to this command
-	</note>
+			<title>Description</title>
+			<para>
+			    Scans through each character in the specified string looking
+			    for special characters, escaping them as needed, mapping
+			    special characters to a quoted hexadecimal equivalent,
+			    returning the result.
+			</para>
+			<para>
+			    This is useful for quoting strings that are going to be
+			    part of a URL.
+			</para>
+			<note> 
+			    You must require the Rivet package in order to gain access to this command
+			</note>
       </refsect1>
-    </refentry>
+	</refentry>
 
     <refentry id="escape_sgml_chars">
       <refnamediv>

Modified: tcl/rivet/trunk/doc/xml/directives.xml
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/doc/xml/directives.xml?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/doc/xml/directives.xml (original)
+++ tcl/rivet/trunk/doc/xml/directives.xml Tue Mar  1 22:04:11 2011
@@ -37,6 +37,8 @@
 	      <arg>BeforeScript</arg>
 	      <arg>AfterScript</arg>
 	      <arg>ErrorScript</arg>
+	      <arg>AbortScript</arg>
+	      <arg>AfterEveryScript</arg>
 	      <arg>UploadDirectory</arg>
 	      <arg>UploadMaxSize</arg>
 	      <arg>UploadFilesToVar</arg>
@@ -214,45 +216,86 @@
 
 	    <varlistentry>
 	      <term>
-		<cmdsynopsis>
-		  <arg choice="plain">ErrorScript</arg>
-		  <arg><replaceable>script</replaceable></arg>
-		</cmdsynopsis>
+				<cmdsynopsis>
+				  <arg choice="plain">ErrorScript</arg>
+				  <arg><replaceable>script</replaceable></arg>
+				</cmdsynopsis>
 	      </term>
 	      <listitem>
-		<para>
-		  When Rivet encounters an error in a script, it
-		  constructs an HTML page with some information about
-		  the error, and the script that was being
-		  evaluated. If an <option>ErrorScript</option> is
-		  specified, it is possible to create custom error
-		  pages.  This may be useful if you want to make sure
-		  that users never view your source code.
-		</para>
-		<para>
-		  In virtual hosts, this option takes precedence over
-		  the global setting.
-		</para>
+				<para>
+				  When Rivet encounters an error in a script, it
+				  constructs an HTML page with some information about
+				  the error, and the script that was being
+				  evaluated. If an <option>ErrorScript</option> is
+				  specified, it is possible to create custom error
+				  pages.  This may be useful if you want to make sure
+				  that users never view your source code.
+				</para>
+				<para>
+				  In virtual hosts, this option takes precedence over
+				  the global setting.
+				</para>
 	      </listitem>
 	    </varlistentry>
 
 	    <varlistentry>
 	      <term>
-		<cmdsynopsis>
-		  <arg choice="plain">UploadDirectory</arg>
-		  <arg><replaceable>directory</replaceable></arg>
-		</cmdsynopsis>
+				<cmdsynopsis>
+				  <arg choice="plain">AfterEveryScript</arg>
+				  <arg><replaceable>script</replaceable></arg>
+				</cmdsynopsis>
 	      </term>
 	      <listitem>
-		<para>Directory to place uploaded files.</para>
-		<para>
-		  In virtual hosts, this option takes precedence over
-		  the global setting.
-		</para>
+				<para>
+					<option>AfterEveryScript</option> is a script that is to
+					be run anyway before requests processing ends. This script
+					is therefore run both when the content generation script
+					completes successfully and when its execution is interrupted
+					by <xref linkend="abort_page" />. The code in this script
+					can tell whether we are running after an abort condition
+					occurred by passing the argument <arg>-aborting</arg> to
+					<xref linkend="abort_page" /> which in turn returns 1 if
+					abort_page had been called earlier in the request processing.
+				</para>
 	      </listitem>
 	    </varlistentry>
 
-	    <varlistentry>
+		<varlistentry>
+			<term>
+				<cmdsynopsis>
+					<arg choice="plain">AbortScript</arg>
+					<arg><replaceable>script</replaceable></arg>
+				</cmdsynopsis>
+			</term>
+			<listitem>
+				<para>
+					Execution of a content generating script can be
+					done by invoking <xref linkend="abort_page" />. When 
+					an <option>AbortScript</option> is defined for the page
+					being generated, control is passed to it as a way
+					to undertake specific action that might be necessary
+					to catch resources left dangling by the sudden interruption.				
+				</para>			
+			</listitem>
+		</varlistentry>
+
+	   <varlistentry>
+	      <term>
+				<cmdsynopsis>
+				  <arg choice="plain">UploadDirectory</arg>
+				  <arg><replaceable>directory</replaceable></arg>
+				</cmdsynopsis>
+	      </term>
+	      <listitem>
+				<para>Directory to place uploaded files.</para>
+				<para>
+		  			In virtual hosts, this option takes precedence over
+		  			the global setting.
+				</para>
+	      </listitem>
+	  </varlistentry>
+
+	  <varlistentry>
 	      <term>
 		<cmdsynopsis>
 		  <arg choice="plain">UploadMaxSize</arg>

Modified: tcl/rivet/trunk/src/apache-2/mod_rivet.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/mod_rivet.c?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/mod_rivet.c (original)
+++ tcl/rivet/trunk/src/apache-2/mod_rivet.c Tue Mar  1 22:04:11 2011
@@ -327,6 +327,7 @@ Rivet_ExecuteAndCheck(Tcl_Interp *interp
          */
 
         errorCodeListObj = Tcl_GetVar2Ex (interp, "errorCode", (char *)NULL, TCL_GLOBAL_ONLY);
+
         /* errorCode is guaranteed to be set to NONE, but let's make sure
          * anyway rather than causing a SIGSEGV
          */
@@ -350,7 +351,17 @@ Rivet_ExecuteAndCheck(Tcl_Interp *interp
             ap_assert (Tcl_ListObjIndex (interp, errorCodeListObj, 1, &errorCodeElementObj)
== TCL_OK);
 
             errorCodeSubString = Tcl_GetString (errorCodeElementObj);
-            if (strcmp (errorCodeSubString, "ABORTPAGE") == 0) {
+            if (strcmp (errorCodeSubString, "ABORTPAGE") == 0) 
+            {
+                if (conf->rivet_abort_script) 
+                {
+                    if (Tcl_EvalObjEx(interp,conf->rivet_abort_script,0) == TCL_ERROR)
+                    {
+                        CONST84 char *errorinfo = Tcl_GetVar( interp, "errorInfo", 0 );
+                        TclWeb_PrintError("<b>Rivet ErrorScript failed!</b>",1,globals->req);
+                        TclWeb_PrintError( errorinfo, 0, globals->req );
+                    }
+                }
                 goto good;
             }
         }
@@ -361,7 +372,6 @@ Rivet_ExecuteAndCheck(Tcl_Interp *interp
 
         /* If we don't have an error script, use the default error handler. */
         if (conf->rivet_error_script ) {
-//          errscript = Tcl_NewStringObj(conf->rivet_error_script, -1);
             errscript = conf->rivet_error_script;
         } else {
             errscript = conf->rivet_default_error_script;
@@ -381,6 +391,15 @@ Rivet_ExecuteAndCheck(Tcl_Interp *interp
 
     /* Make sure to flush the output if buffer_add was the only output */
 good:
+    
+    if (conf->after_every_script) {
+        if (Tcl_EvalObjEx(interp,conf->after_every_script,0) == TCL_ERROR)
+        {
+            CONST84 char *errorinfo = Tcl_GetVar( interp, "errorInfo", 0 );
+            TclWeb_PrintError("<b>Rivet AfterEveryScript failed!</b>",1,globals->req);
+            TclWeb_PrintError( errorinfo, 0, globals->req );
+        }
+    }
 
     if (!globals->req->headers_set && (globals->req->charset != NULL))
{
         TclWeb_SetHeaderType (apr_pstrcat(globals->req->req->pool,"text/html;",globals->req->charset,NULL),globals->req);
@@ -565,6 +584,8 @@ Rivet_ParseExecFile(TclWebRequest *req, 
 static void
 Rivet_CleanupRequest( request_rec *r )
 {
+
+
 #if 0
     apr_table_t *t;
     apr_array_header_t *arr;
@@ -631,6 +652,8 @@ Rivet_CopyConfig( rivet_server_conf *old
     newrsc->rivet_before_script = oldrsc->rivet_before_script;
     newrsc->rivet_after_script = oldrsc->rivet_after_script;
     newrsc->rivet_error_script = oldrsc->rivet_error_script;
+    newrsc->rivet_abort_script = oldrsc->rivet_abort_script;
+    newrsc->after_every_script = oldrsc->after_every_script;
 
     newrsc->user_scripts_updated = oldrsc->user_scripts_updated;
 
@@ -670,6 +693,10 @@ Rivet_MergeDirConfigVars(apr_pool_t *p, 
         add->rivet_after_script : base->rivet_after_script;
     new->rivet_error_script = add->rivet_error_script ?
         add->rivet_error_script : base->rivet_error_script;
+    new->rivet_abort_script = add->rivet_abort_script ?
+        add->rivet_abort_script : base->rivet_abort_script;
+    new->after_every_script = add->after_every_script ?
+        add->after_every_script : base->after_every_script;
 
     new->user_scripts_updated = add->user_scripts_updated ?
         add->user_scripts_updated : base->user_scripts_updated;
@@ -735,6 +762,8 @@ Rivet_CreateConfig(apr_pool_t *p, server
     rsc->rivet_before_script        = NULL;
     rsc->rivet_after_script         = NULL;
     rsc->rivet_error_script         = NULL;
+    rsc->rivet_abort_script         = NULL;
+    rsc->after_every_script         = NULL;
 
     rsc->user_scripts_updated = 0;
 
@@ -865,6 +894,15 @@ Rivet_PerInterpInit(server_rec *s, rivet
     /* Set up interpreter associated data */
     globals = apr_pcalloc(p, sizeof(rivet_interp_globals));
     Tcl_SetAssocData(interp, "rivet", NULL, globals);
+    
+    /* 
+     * abort_page status variables in globals are set here and then 
+     * reset in Rivet_SendContent just before the request processing is 
+     * completed 
+     */
+
+    globals->page_aborting = 0;
+    globals->abort_code = NULL;
 
     /* Eval Rivet's init.tcl file to load in the Tcl-level commands. */
 
@@ -980,6 +1018,10 @@ Rivet_SetScript (apr_pool_t *pool, rivet
         objarg = Rivet_AssignStringToConf(&(rsc->rivet_error_script),string);
     } else if( STREQU( script, "ServerInitScript" ) ) {
         objarg = Rivet_AssignStringToConf(&(rsc->rivet_server_init_script),string);
+    } else if( STREQU( script, "AbortScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->rivet_abort_script),string);
+    } else if( STREQU( script, "AfterEveryScript" ) ) {
+        objarg = Rivet_AssignStringToConf(&(rsc->after_every_script),string);
     }
 
     if( !objarg ) return string;
@@ -1230,6 +1272,12 @@ Rivet_MergeConfig(apr_pool_t *p, void *b
     rsc->rivet_default_error_script = overrides->rivet_default_error_script ?
         overrides->rivet_default_error_script : base->rivet_default_error_script;
 
+    rsc->rivet_abort_script = overrides->rivet_abort_script ?
+        overrides->rivet_abort_script : base->rivet_abort_script;
+
+    rsc->after_every_script = overrides->after_every_script ?
+        overrides->after_every_script : base->after_every_script;
+
     /* cache_size is global, and set up later. */
     /* cache_free is not set up at this point. */
 
@@ -1816,6 +1864,14 @@ Rivet_SendContent(request_rec *r)
     retval = OK;
 sendcleanup:
     globals->req->content_sent = 0;
+
+    globals->page_aborting = 0;
+    if (globals->abort_code != NULL)
+    {
+        Tcl_DecrRefCount(globals->abort_code);
+        globals->abort_code = NULL;
+    }
+
     Tcl_MutexUnlock(&sendMutex);
     return retval;
 }

Modified: tcl/rivet/trunk/src/apache-2/mod_rivet.h
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/mod_rivet.h?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/mod_rivet.h (original)
+++ tcl/rivet/trunk/src/apache-2/mod_rivet.h Tue Mar  1 22:04:11 2011
@@ -56,38 +56,44 @@ typedef struct _rivet_server_conf {
     Tcl_Obj *rivet_global_init_script;	/* run once when apache is started */
     Tcl_Obj *rivet_child_init_script;
     Tcl_Obj *rivet_child_exit_script;
-    Tcl_Obj *rivet_before_script;	/* script run before each page	*/
-    Tcl_Obj *rivet_after_script;	/*            after		*/
-    Tcl_Obj *rivet_error_script;	/*            for errors	*/
+    Tcl_Obj *rivet_before_script;	/* script run before each page      */
+    Tcl_Obj *rivet_after_script;	/*            after                 */
+    Tcl_Obj *rivet_error_script;	/*            for errors            */
+    Tcl_Obj *rivet_abort_script;	/* script run upon abort_page call  */
+    Tcl_Obj *after_every_script;	/* script to be run always	    */
+
+    /*  This flag is used with the above directives.  
+        If any of them have changed, it gets set. */
 
-    /* This flag is used with the above directives.  If any of them
-       have changed, it gets set. */
     int user_scripts_updated;
 
-    Tcl_Obj *rivet_default_error_script;    /* for errors */
+    Tcl_Obj *rivet_default_error_script; /* for errors */
     int *cache_size;
     int *cache_free;
     int upload_max;
     int upload_files_to_var;
     int separate_virtual_interps;
-    int honor_header_only_reqs;		    /* default: 0 */
+    int honor_header_only_reqs;		/* default: 0 */
     char *server_name;
     const char *upload_dir;
     apr_table_t *rivet_server_vars;
     apr_table_t *rivet_dir_vars;
     apr_table_t *rivet_user_vars;
-    char **objCacheList;		    /* Array of cached objects (for priority handling) */
-    Tcl_HashTable *objCache;		    /* Objects cache - the key is the script name */
+    char **objCacheList;		/* Array of cached objects (for priority handling) */
+    Tcl_HashTable *objCache;		/* Objects cache - the key is the script name */
 
-    Tcl_Channel *outchannel;		    /* stuff for buffering output */
+    Tcl_Channel *outchannel;		/* stuff for buffering output */
 } rivet_server_conf;
 
 /* eventually we will transfer 'global' variables in here and
    'de-globalize' them */
 
 typedef struct _rivet_interp_globals {
-    request_rec *r;			    /* request rec */
-    TclWebRequest *req;			    /* TclWeb API request */
+    request_rec*    r;			/* request rec */
+    TclWebRequest*  req;		/* TclWeb API request */
+    int             page_aborting;	/* set by abort_page. */
+					/* to be reset by Rivet_SendContent */
+    Tcl_Obj*        abort_code;
 } rivet_interp_globals;
 
 int Rivet_ParseExecFile(TclWebRequest *req, char *filename, int toplevel);

Modified: tcl/rivet/trunk/src/apache-2/rivetCore.c
URL: http://svn.apache.org/viewvc/tcl/rivet/trunk/src/apache-2/rivetCore.c?rev=1076029&r1=1076028&r2=1076029&view=diff
==============================================================================
--- tcl/rivet/trunk/src/apache-2/rivetCore.c (original)
+++ tcl/rivet/trunk/src/apache-2/rivetCore.c Tue Mar  1 22:04:11 2011
@@ -591,200 +591,200 @@ TCL_CMD_HEADER( Rivet_ApacheTable )
     int subcommandindex;
 
     static CONST84 char *SubCommand[] = {
-	"get",
-	"set",
-	"exists",
-	"unset",
-	"names",
-	"array_get",
-	"clear",
-	NULL
+        "get",
+        "set",
+        "exists",
+        "unset",
+        "names",
+        "array_get",
+        "clear",
+        NULL
     };
 
     enum subcommand {
-	SUB_GET,
-	SUB_SET,
-	SUB_EXISTS,
-	SUB_UNSET,
-	SUB_NAMES,
-	SUB_ARRAY_GET,
-	SUB_CLEAR
+        SUB_GET,
+        SUB_SET,
+        SUB_EXISTS,
+        SUB_UNSET,
+        SUB_NAMES,
+        SUB_ARRAY_GET,
+        SUB_CLEAR
     };
 
     static CONST84 char *tableNames[] = {
-	"notes",
-	"headers_in",
-	"headers_out",
-	"err_headers_out",
-	"subprocess_env",
-	NULL
+        "notes",
+        "headers_in",
+        "headers_out",
+        "err_headers_out",
+        "subprocess_env",
+        NULL
     };
 
     int tableindex;
 
     enum tablename {
-	TABLE_NOTES,
-	TABLE_HEADERS_IN,
-	TABLE_HEADERS_OUT,
-	TABLE_ERR_HEADERS_OUT,
-	TABLE_SUBPROCESS_ENV
+        TABLE_NOTES,
+        TABLE_HEADERS_IN,
+        TABLE_HEADERS_OUT,
+        TABLE_ERR_HEADERS_OUT,
+        TABLE_SUBPROCESS_ENV
     };
 
     rivet_interp_globals *globals = Tcl_GetAssocData(interp, "rivet", NULL);
 
     if ((objc < 3) || (objc > 5)) {
-	Tcl_WrongNumArgs(interp, 1, objv, "option tablename ?args?");
-	return TCL_ERROR;
+        Tcl_WrongNumArgs(interp, 1, objv, "option tablename ?args?");
+        return TCL_ERROR;
     }
 
-    if (Tcl_GetIndexFromObj(interp, objv[1], SubCommand,
-			"get|set|unset|list",
-			0, &subcommandindex) == TCL_ERROR) {
-	return TCL_ERROR;
+    if (Tcl_GetIndexFromObj(interp, objv[1],SubCommand,
+                        "get|set|unset|list",
+			            0, &subcommandindex) == TCL_ERROR) {
+        return TCL_ERROR;
     }
 
     if (Tcl_GetIndexFromObj (interp, objv[2], tableNames,
-			"notes|headers_in|headers_out|err_header_out|subprocess_env",
-			0, &tableindex) == TCL_ERROR) {
-	return TCL_ERROR;
+                    "notes|headers_in|headers_out|err_header_out|subprocess_env",
+                    0, &tableindex) == TCL_ERROR) {
+	    return TCL_ERROR;
     }
 
     switch ((enum tablename)tableindex)
     {
-	case TABLE_NOTES: {
-	    table = globals->r->notes;
-	    break;
-	}
-
-	case TABLE_HEADERS_IN: {
-	    table = globals->r->headers_in;
-	    break;
-	}
-
-	case TABLE_HEADERS_OUT: {
-	    table = globals->r->headers_out;
-	    break;
-	}
-
-	case TABLE_ERR_HEADERS_OUT: {
-	    table = globals->r->err_headers_out;
-	    break;
-	}
-
-	case TABLE_SUBPROCESS_ENV: {
-	    table = globals->r->subprocess_env;
-	    break;
-	}
+        case TABLE_NOTES: {
+            table = globals->r->notes;
+            break;
+        }
+
+        case TABLE_HEADERS_IN: {
+            table = globals->r->headers_in;
+            break;
+        }
+
+        case TABLE_HEADERS_OUT: {
+            table = globals->r->headers_out;
+            break;
+        }
+
+        case TABLE_ERR_HEADERS_OUT: {
+            table = globals->r->err_headers_out;
+            break;
+        }
+
+        case TABLE_SUBPROCESS_ENV: {
+            table = globals->r->subprocess_env;
+            break;
+        }
     }
 
     switch ((enum subcommand)subcommandindex)
     {
-	case SUB_GET: {
-	    const char *key;
-	    const char *value;
-
-	    if (objc != 4) {
-		Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
-		return TCL_ERROR;
-	    }
-
-	    key = Tcl_GetString (objv[3]);
-	    value = apr_table_get (table, key);
-
-	    if (value != NULL) {
-		Tcl_SetObjResult (interp, Tcl_NewStringObj (value, -1));
-	    }
-	    break;
-	}
-
-	case SUB_EXISTS: {
-	    const char *key;
-	    const char *value;
-
-	    if (objc != 4) {
-		Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
-		return TCL_ERROR;
-	    }
-
-	    key = Tcl_GetString (objv[3]);
-	    value = apr_table_get (table, key);
-
-	    Tcl_SetObjResult (interp, Tcl_NewBooleanObj (value != NULL));
-	    break;
-	}
-
-
-	case SUB_SET: {
-	    int i;
-	    char *key;
-	    char *value;
-
-	    if (objc == 4) {
-		int listObjc;
-		Tcl_Obj **listObjv;
-
-		if (Tcl_ListObjGetElements (interp, objv[3], &listObjc, &listObjv) == TCL_ERROR)
{
-		    return TCL_ERROR;
-		}
-
-		if (listObjc % 2 == 1) {
-		    Tcl_SetObjResult (interp, Tcl_NewStringObj ("list must have even number of elements",
-1));
-		    return TCL_ERROR;
-		}
-
-		for (i = 0; i < listObjc; i += 2) {
-		    apr_table_set (table, Tcl_GetString (listObjv[i]), Tcl_GetString (listObjv[i+1]));
-		}
-
-		break;
-	    }
-
-	    if (objc != 5) {
-		Tcl_WrongNumArgs(interp, 2, objv, "tablename key value");
-		return TCL_ERROR;
-	    }
-
-	    key = Tcl_GetString (objv[3]);
-	    value = Tcl_GetString (objv[4]);
-
-	    apr_table_set (table, key, value);
-	    break;
-	}
-
-	case SUB_UNSET: {
-	    char *key;
-
-	    if (objc != 4) {
-		Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
-		return TCL_ERROR;
-	    }
-
-	    key = Tcl_GetString (objv[3]);
-	    apr_table_unset (table, key);
-	    break;
-	}
+        case SUB_GET: {
+            const char *key;
+            const char *value;
+
+            if (objc != 4) {
+            Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
+            return TCL_ERROR;
+            }
+
+            key = Tcl_GetString (objv[3]);
+            value = apr_table_get (table, key);
+
+            if (value != NULL) {
+            Tcl_SetObjResult (interp, Tcl_NewStringObj (value, -1));
+            }
+            break;
+        }
+
+        case SUB_EXISTS: {
+            const char *key;
+            const char *value;
+
+            if (objc != 4) {
+            Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
+            return TCL_ERROR;
+            }
+
+            key = Tcl_GetString (objv[3]);
+            value = apr_table_get (table, key);
+
+            Tcl_SetObjResult (interp, Tcl_NewBooleanObj (value != NULL));
+            break;
+        }
+
+
+        case SUB_SET: {
+            int i;
+            char *key;
+            char *value;
+
+            if (objc == 4) {
+                int listObjc;
+                Tcl_Obj **listObjv;
+
+                if (Tcl_ListObjGetElements (interp, objv[3], &listObjc, &listObjv)
== TCL_ERROR) {
+                    return TCL_ERROR;
+                }
+
+                if (listObjc % 2 == 1) {
+                    Tcl_SetObjResult (interp, Tcl_NewStringObj ("list must have even number
of elements", -1));
+                    return TCL_ERROR;
+                }
+
+                for (i = 0; i < listObjc; i += 2) {
+                    apr_table_set (table, Tcl_GetString (listObjv[i]), Tcl_GetString (listObjv[i+1]));
+                }
+
+                break;
+            }
+
+            if (objc != 5) {
+                Tcl_WrongNumArgs(interp, 2, objv, "tablename key value");
+                return TCL_ERROR;
+            }
+
+            key = Tcl_GetString (objv[3]);
+            value = Tcl_GetString (objv[4]);
+
+            apr_table_set (table, key, value);
+            break;
+        }
+
+        case SUB_UNSET: {
+            char *key;
+
+            if (objc != 4) {
+                Tcl_WrongNumArgs(interp, 2, objv, "tablename key");
+                return TCL_ERROR;
+            }
+
+            key = Tcl_GetString (objv[3]);
+            apr_table_unset (table, key);
+            break;
+        }
 
-	case SUB_NAMES: {
+        case SUB_NAMES: {
             Tcl_Obj *list = Tcl_NewObj ();
 
-	    apr_table_do(append_key_callback, (void*)list, table, NULL);
+            apr_table_do(append_key_callback, (void*)list, table, NULL);
 
-	    Tcl_SetObjResult (interp, list);
-	    break;
-	}
+            Tcl_SetObjResult (interp, list);
+            break;
+        }
 
-	case SUB_ARRAY_GET: {
+        case SUB_ARRAY_GET: {
             Tcl_Obj *list = Tcl_NewObj ();
 
-	    apr_table_do(append_key_value_callback, (void*)list, table, NULL);
+            apr_table_do(append_key_value_callback, (void*)list, table, NULL);
 
-	    Tcl_SetObjResult (interp, list);
-	    break;
-	}
-
-	case SUB_CLEAR: {
-	    apr_table_clear (table);
-	}
+            Tcl_SetObjResult (interp, list);
+            break;
+        }
+
+        case SUB_CLEAR: {
+            apr_table_clear (table);
+        }
     }
 
     return TCL_OK;
@@ -826,28 +826,28 @@ TCL_CMD_HEADER( Rivet_Upload )
     Tcl_Obj *result = NULL;
 
     static CONST84 char *SubCommand[] = {
-	"channel",
-	"save",
-	"data",
-	"exists",
-	"size",
-	"type",
-	"filename",
-	"tempname",
-	"names",
-	NULL
+        "channel",
+        "save",
+        "data",
+        "exists",
+        "size",
+        "type",
+        "filename",
+        "tempname",
+        "names",
+        NULL
     };
 
     enum subcommand {
-	CHANNEL,
-	SAVE,
-	DATA,
-	EXISTS,
-	SIZE,
-	TYPE,
-	FILENAME,
-	TEMPNAME,
-	NAMES
+        CHANNEL,
+        SAVE,
+        DATA,
+        EXISTS,
+        SIZE,
+        TYPE,
+        FILENAME,
+        TEMPNAME,
+        NAMES
     };
 
     rivet_interp_globals *globals = Tcl_GetAssocData(interp, "rivet", NULL);
@@ -863,96 +863,115 @@ TCL_CMD_HEADER( Rivet_Upload )
     /* Excluded case is NAMES. */
 
     if ((enum subcommand)subcommandindex == CHANNEL 	||
-	(enum subcommand)subcommandindex == SAVE 	||
-	(enum subcommand)subcommandindex == DATA 	||
-	(enum subcommand)subcommandindex == EXISTS 	||
-	(enum subcommand)subcommandindex == SIZE 	||
-	(enum subcommand)subcommandindex == TYPE 	||
-	(enum subcommand)subcommandindex == FILENAME 	||
-	(enum subcommand)subcommandindex == TEMPNAME)
+        (enum subcommand)subcommandindex == SAVE 	    ||
+        (enum subcommand)subcommandindex == DATA 	    ||
+        (enum subcommand)subcommandindex == EXISTS 	    ||
+        (enum subcommand)subcommandindex == SIZE 	    ||
+        (enum subcommand)subcommandindex == TYPE 	    ||
+        (enum subcommand)subcommandindex == FILENAME 	||
+        (enum subcommand)subcommandindex == TEMPNAME)
     {
-	varname = Tcl_GetString(objv[2]);
-	if ((enum subcommand)subcommandindex != EXISTS)
-	{
-	    if (TclWeb_PrepareUpload(varname, globals->req) != TCL_OK)
-	    {
-		Tcl_AddErrorInfo(interp, "Unable to find variable");
-		return TCL_ERROR;
-	    }
-	}
-
-	/* If it's not the 'save' command, then it has to have an objc
-	   of 3. */
-	if ((enum subcommand)subcommandindex != SAVE && objc != 3)
-	{
-	    Tcl_WrongNumArgs(interp, 2, objv, "varname");
-	    return TCL_ERROR;
-	}
+        varname = Tcl_GetString(objv[2]);
+        if ((enum subcommand)subcommandindex != EXISTS)
+        {
+            if (TclWeb_PrepareUpload(varname, globals->req) != TCL_OK)
+            {
+            Tcl_AddErrorInfo(interp, "Unable to find variable");
+            return TCL_ERROR;
+            }
+        }
+
+        /* If it's not the 'save' command, then it has to have an objc
+           of 3. */
+        if ((enum subcommand)subcommandindex != SAVE && objc != 3)
+        {
+            Tcl_WrongNumArgs(interp, 2, objv, "varname");
+            return TCL_ERROR;
+        }
     }
 
     result = Tcl_NewObj();
 
     switch ((enum subcommand)subcommandindex)
     {
-    case CHANNEL: {
-	Tcl_Channel chan;
-	char *channelname = NULL;
-
-	if (TclWeb_UploadChannel(varname, &chan, globals->req) != TCL_OK) {
-	    return TCL_ERROR;
-	}
-	channelname = (char *)Tcl_GetChannelName(chan);
-	Tcl_SetStringObj(result, channelname, -1);
-	break;
-    }
-    case SAVE:
-	/* save data to a specified filename  */
-	if (objc != 4) {
-	    Tcl_WrongNumArgs(interp, 2, objv, "uploadname filename");
-	    return TCL_ERROR;
-	}
-
-	if (TclWeb_UploadSave(varname, objv[3], globals->req) != TCL_OK)
-	{
-	    return TCL_ERROR;
-	}
-	break;
-    case DATA:
-	if (TclWeb_UploadData(varname, result, globals->req) != TCL_OK) {
-	    return TCL_ERROR;
-	}
-	break;
-    case EXISTS:
-	if (TclWeb_PrepareUpload(varname, globals->req) != TCL_OK)
-	{
-	    Tcl_SetIntObj(result, 0);
-	} else {
-	    Tcl_SetIntObj(result, 1);
-	}
-	break;
-    case SIZE:
-	TclWeb_UploadSize(result, globals->req);
-	break;
-    case TYPE:
-	TclWeb_UploadType(result, globals->req);
-	break;
-    case FILENAME:
-	TclWeb_UploadFilename(result, globals->req);
-	break;
-    case TEMPNAME:
-	TclWeb_UploadTempname(result,globals->req);
-	break;
-    case NAMES:
-	if (objc != 2)
-	{
-	    Tcl_WrongNumArgs(interp, 1, objv, "names");
-	    return TCL_ERROR;
-	}
-	TclWeb_UploadNames(result, globals->req);
-	break;
-    default:
-	Tcl_WrongNumArgs(interp, 1, objv,
-			 "channel|save ?name?|data|exists|size|type|filename|names|tempname");
+        case CHANNEL: 
+        {
+            Tcl_Channel chan;
+            char *channelname = NULL;
+
+            if (TclWeb_UploadChannel(varname, &chan, globals->req) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            channelname = (char *)Tcl_GetChannelName(chan);
+            Tcl_SetStringObj(result, channelname, -1);
+            break;
+        }
+        case SAVE:
+        {
+            /* save data to a specified filename  */
+            if (objc != 4) {
+                Tcl_WrongNumArgs(interp, 2, objv, "uploadname filename");
+                return TCL_ERROR;
+            }
+
+            if (TclWeb_UploadSave(varname, objv[3], globals->req) != TCL_OK)
+            {
+                return TCL_ERROR;
+            }
+            break;
+        }
+        case DATA:
+        {
+            if (TclWeb_UploadData(varname, result, globals->req) != TCL_OK) {
+                return TCL_ERROR;
+            }
+            break;
+        }
+        case EXISTS:
+        {
+            if (TclWeb_PrepareUpload(varname, globals->req) != TCL_OK)
+            {
+                Tcl_SetIntObj(result, 0);
+            } else {
+                Tcl_SetIntObj(result, 1);
+            }
+            break;
+        }
+        case SIZE:
+        {
+            TclWeb_UploadSize(result, globals->req);
+            break;
+        }
+        case TYPE:
+        {
+            TclWeb_UploadType(result, globals->req);
+            break;
+        }
+        case FILENAME:
+        {
+            TclWeb_UploadFilename(result, globals->req);
+            break;
+        }
+        case TEMPNAME:
+        {
+            TclWeb_UploadTempname(result,globals->req);
+            break;
+        }
+        case NAMES:
+        {
+            if (objc != 2)
+            {
+                Tcl_WrongNumArgs(interp, 1, objv, "names");
+                return TCL_ERROR;
+            }
+            TclWeb_UploadNames(result, globals->req);
+            break;
+        }
+        default:
+        {
+            Tcl_WrongNumArgs(interp, 1, objv,
+                 "channel|save ?name?|data|exists|size|type|filename|names|tempname");
+        }
     }
     Tcl_SetObjResult(interp, result);
     return TCL_OK;
@@ -983,7 +1002,7 @@ TCL_CMD_HEADER ( Rivet_RawPost )
     data = TclWeb_GetRawPost(globals->req);
 
     if (!data) {
-	data = "";
+        data = "";
     }
     retval = Tcl_NewStringObj(data, -1);
     Tcl_SetObjResult(interp, retval);
@@ -1012,8 +1031,8 @@ TCL_CMD_HEADER( Rivet_NoBody )
     rivet_interp_globals *globals = Tcl_GetAssocData(interp, "rivet", NULL);
 
     if (globals->req->content_sent == 1) {
-	Tcl_AddErrorInfo(interp, "Content already sent");
-	return TCL_ERROR;
+        Tcl_AddErrorInfo(interp, "Content already sent");
+        return TCL_ERROR;
     }
 
     globals->req->content_sent = 1;
@@ -1041,14 +1060,52 @@ TCL_CMD_HEADER( Rivet_NoBody )
 
 TCL_CMD_HEADER( Rivet_AbortPageCmd )
 {
+    rivet_interp_globals *globals = Tcl_GetAssocData( interp, "rivet", NULL );
     static char *errorMessage = "Page generation terminated by abort_page directive";
 
-    if (objc != 1)
+    if (objc > 2)
     {
-	Tcl_WrongNumArgs(interp, 1, objv, "");
-	return TCL_ERROR;
+        Tcl_WrongNumArgs(interp, 1, objv, "");
+        return TCL_ERROR;
+    }
+
+    if (objc == 2)
+    {
+        char* cmd_arg = Tcl_GetStringFromObj(objv[1],NULL);
+        
+        if (strcmp(cmd_arg,"-aborting") == 0)
+        {
+            Tcl_SetObjResult (interp,Tcl_NewBooleanObj(globals->page_aborting));
+            return TCL_OK;
+        }
+ 
+    /* 
+     * we assume abort_code to be null, as abort_page shouldn't run twice while
+     * processing the same request 
+     */
+       
+        if (globals->abort_code == NULL)
+        {
+            globals->abort_code = objv[1];
+            Tcl_IncrRefCount(globals->abort_code);
+        }
     }
 
+    /* 
+     * If page_aborting is true then this is the second call to abort_page
+     * processing the same request: we ignore it and return a normal
+     * completion code
+     */
+
+    if (globals->page_aborting)
+    {
+        return TCL_OK;
+    }
+
+    /* this is the first (and supposedly unique) abort_page call during this request */
+
+    globals->page_aborting = 1;
+
     Tcl_AddErrorInfo (interp, errorMessage);
     Tcl_SetErrorCode (interp, "RIVET", "ABORTPAGE", errorMessage, (char *)NULL);
     return TCL_ERROR;
@@ -1056,6 +1113,28 @@ TCL_CMD_HEADER( Rivet_AbortPageCmd )
 
 /*
  *-----------------------------------------------------------------------------
+ * Rivet_AbortCodeCmd -- 
+ *
+ * Returns the abort code stored internally by passing a user defined parameter 
+ * to the command 'abort_page'.
+ *
+ *
+ *-----------------------------------------------------------------------------
+ */
+TCL_CMD_HEADER( Rivet_AbortCodeCmd )
+{
+    rivet_interp_globals *globals = Tcl_GetAssocData( interp, "rivet", NULL );
+    
+    if (globals->abort_code != NULL)
+    {
+        Tcl_SetObjResult(interp,globals->abort_code);
+    }
+
+    return TCL_OK;
+}
+
+/*
+ *-----------------------------------------------------------------------------
  *
  * Rivet_EnvCmd --
  *
@@ -1078,8 +1157,8 @@ TCL_CMD_HEADER( Rivet_EnvCmd )
     char *val;
 
     if( objc != 2 ) {
-	Tcl_WrongNumArgs( interp, 1, objv, "variable" );
-	return TCL_ERROR;
+        Tcl_WrongNumArgs( interp, 1, objv, "variable" );
+        return TCL_ERROR;
     }
 
     key = Tcl_GetStringFromObj( objv[1], NULL );
@@ -1114,8 +1193,8 @@ TCL_CMD_HEADER( Rivet_VirtualFilenameCmd
     char *virtual;
 
     if( objc != 2 ) {
-	Tcl_WrongNumArgs( interp, 1, objv, "filename" );
-	return TCL_ERROR;
+        Tcl_WrongNumArgs( interp, 1, objv, "filename" );
+        return TCL_ERROR;
     }
 
     virtual   = Tcl_GetStringFromObj( objv[1], NULL );
@@ -1193,7 +1272,7 @@ TCL_CMD_HEADER( Rivet_LogErrorCmd )
     {
       case EMERG:
         apLogLevel = APLOG_EMERG;
-	break;
+        break;
 
       case ALERT:
         apLogLevel = APLOG_ALERT;
@@ -1389,6 +1468,7 @@ Rivet_InitCore( Tcl_Interp *interp )
 #endif
 
     TCL_OBJ_CMD( "abort_page", Rivet_AbortPageCmd );
+    TCL_OBJ_CMD( "abort_code", Rivet_AbortCodeCmd );
     TCL_OBJ_CMD( "virtual_filename", Rivet_VirtualFilenameCmd );
 
     return TCL_OK;



---------------------------------------------------------------------
To unsubscribe, e-mail: rivet-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: rivet-cvs-help@tcl.apache.org


Mime
View raw message