You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mod_dtcl-cvs@tcl.apache.org by da...@apache.org on 2001/06/21 19:47:20 UTC

cvs commit: tcl-moddtcl/docs documentation.txt

davidw      01/06/21 10:47:20

  Modified:    .        apache_cookie.c apache_multipart_buffer.c
                        apache_request.c apache_request.h mod_dtcl.c
                        mod_dtcl.h tcl_commands.c tcl_commands.h
               docs     documentation.txt
  Log:
  Initial commit of upload command.  Things are in a bit of a broken
  state at the moment.  Cleaned up some extra white space too.
  
  Revision  Changes    Path
  1.4       +10 -10    tcl-moddtcl/apache_cookie.c
  
  Index: apache_cookie.c
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/apache_cookie.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- apache_cookie.c	2001/03/15 19:36:55	1.3
  +++ apache_cookie.c	2001/06/21 17:47:08	1.4
  @@ -6,7 +6,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -78,7 +78,7 @@
       char *retval = NULL;
       int ix = key[0] == '-' ? 1 : 0;
   
  -    switch (key[ix]) { 
  +    switch (key[ix]) {
       case 'n':
   	cookie_get_set(c->name, val);
   	break;
  @@ -96,14 +96,14 @@
   	break;
       case 's':
   	if(val) {
  -	    c->secure = 
  +	    c->secure =
   		!strcaseEQ(val, "off") &&
   		!strcaseEQ(val, "0");
   	}
   	retval = c->secure ? "on" : "";
   	break;
       default:
  -	ap_log_rerror(APC_ERROR, 
  +	ap_log_rerror(APC_ERROR,
   		      "[libapreq] unknown cookie pair: `%s' => `%s'", key, val);
       };
   
  @@ -114,7 +114,7 @@
   {
       va_list args;
       ApacheRequest req;
  -    ApacheCookie *c = 
  +    ApacheCookie *c =
   	ap_pcalloc(r->pool, sizeof(ApacheCookie));
   
       req.r = r;
  @@ -144,7 +144,7 @@
   ApacheCookieJar *ApacheCookie_parse(request_rec *r, const char *data)
   {
       const char *pair;
  -    ApacheCookieJar *retval = 
  +    ApacheCookieJar *retval =
   	ap_make_array(r->pool, 1, sizeof(ApacheCookie *));
   
       if (!data) {
  @@ -192,7 +192,7 @@
           cookie_push_arr(arr, ap_pstrcat(p, name, "=", val, NULL)); \
       }
   
  -static char * escape_url(pool *p, char *val) 
  +static char * escape_url(pool *p, char *val)
   {
     char *result = ap_os_escape_path(p, val?val:"", 1);
     char *end = result + strlen(result);
  @@ -248,15 +248,15 @@
   
       cookie = ap_pstrcat(p, escape_url(p, c->name), "=", NULL);
       for (i=0; i<c->values->nelts; i++) {
  -	cookie = ap_pstrcat(p, cookie, 
  -			    escape_url(p, ((char**)c->values->elts)[i]), 
  +	cookie = ap_pstrcat(p, cookie,
  +			    escape_url(p, ((char**)c->values->elts)[i]),
   			    (i < (c->values->nelts-1) ? "&" : NULL),
   			    NULL);
       }
   
       retval = cookie;
       for (i=0; i<values->nelts; i++) {
  -	retval = ap_pstrcat(p, retval, "; ", 
  +	retval = ap_pstrcat(p, retval, "; ",
   			    ((char**)values->elts)[i], NULL);
       }
   
  
  
  
  1.5       +10 -11    tcl-moddtcl/apache_multipart_buffer.c
  
  Index: apache_multipart_buffer.c
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/apache_multipart_buffer.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- apache_multipart_buffer.c	2001/03/15 19:36:56	1.4
  +++ apache_multipart_buffer.c	2001/06/21 17:47:09	1.5
  @@ -6,7 +6,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -70,7 +70,7 @@
       int needlen = strlen(needle);
       int len = haystacklen;
       char *ptr = haystack;
  -    
  +
       /* iterate through first character matches */
       while( (ptr = memchr(ptr, needle[0], len)) ) {
   	/* calculate length after match */
  @@ -100,10 +100,10 @@
       if(self->bytes_in_buffer > 0 && self->buf_begin != self->buffer)
   	memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
       self->buf_begin = self->buffer;
  -    
  +
       /* calculate the free space in the buffer */
       bytes_to_read = self->bufsize - self->bytes_in_buffer;
  -    
  +
       /* read the required number of bytes */
       if(bytes_to_read > 0) {
   	char *buf = self->buffer + self->bytes_in_buffer;
  @@ -158,7 +158,7 @@
   	self->buf_begin = ptr;
   	self->bytes_in_buffer = 0;
       }
  -    
  +
       return line;
   }
   
  @@ -171,7 +171,7 @@
   	fill_buffer(self);
   	ptr = next_line(self);
       }
  -    
  +
   #ifdef DEBUG
       ap_log_rerror(MPB_ERROR, "get_line: '%s'", ptr);
   #endif
  @@ -182,9 +182,8 @@
   /* finds a boundary */
   int find_boundary(multipart_buffer *self, char *boundary)
   {
  -    int len, bound_len = strlen(boundary);
       char *line;
  -    
  +
       /* loop thru lines */
       while( (line = get_line(self)) ) {
   #ifdef DEBUG
  @@ -193,7 +192,7 @@
   #endif
   
         /* finished if we found the boundary */
  -      if(strcmp(line, boundary) == 0)
  +      if(strEQ(line, boundary))
   	  return 1;
       }
   
  @@ -249,7 +248,7 @@
   			  "multipart_buffer_headers: '%s' = '%s'",
   			  key, value);
   #endif
  -	    
  +
   	    ap_table_add(tab, key, value);
   	}
   	else {
  @@ -283,7 +282,7 @@
   
       /* maximum number of bytes we are reading */
       len = max < bytes-1 ? max : bytes-1;
  -    
  +
       /* if we read any data... */
       if(len > 0) {
   	/* copy the data */
  
  
  
  1.7       +43 -42    tcl-moddtcl/apache_request.c
  
  Index: apache_request.c
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/apache_request.c,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- apache_request.c	2001/06/04 09:54:46	1.6
  +++ apache_request.c	2001/06/21 17:47:09	1.7
  @@ -6,7 +6,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -84,7 +84,7 @@
   	    return HTTP_REQUEST_ENTITY_TOO_LARGE;
   	}
   
  -	*rbuf = ap_pcalloc(r->pool, length + 1); 
  +	*rbuf = ap_pcalloc(r->pool, length + 1);
   
   	ap_hard_timeout("[libapreq] util_read", r);
   
  @@ -112,7 +112,7 @@
       char *tmp;
   
       if (r->path_info && *r->path_info) {
  -	int path_info_start = ap_find_path_info(r->uri, r->path_info); 
  +	int path_info_start = ap_find_path_info(r->uri, r->path_info);
   	tmp = ap_pstrndup(r->pool, r->uri, path_info_start);
       }
       else {
  @@ -133,18 +133,18 @@
       return ap_table_get(req->parms, key);
   }
   
  -static int make_params(void *data, const char *key, const char *val) 
  -{                        
  -    array_header *arr = (array_header *)data; 
  -    *(char **)ap_push_array(arr) = (char *)val; 
  -    return 1; 
  -} 
  +static int make_params(void *data, const char *key, const char *val)
  +{
  +    array_header *arr = (array_header *)data;
  +    *(char **)ap_push_array(arr) = (char *)val;
  +    return 1;
  +}
   
   array_header *ApacheRequest_params(ApacheRequest *req, const char *key)
   {
       array_header *values = ap_make_array(req->r->pool, 4, sizeof(char *));
       ApacheRequest_parse(req);
  -    ap_table_do(make_params, (void*)values, req->parms, key, NULL); 
  +    ap_table_do(make_params, (void*)values, req->parms, key, NULL);
       return values;
   }
   
  @@ -155,7 +155,7 @@
       int i;
   
       for (i=0; i<values->nelts; i++) {
  -	retval = ap_pstrcat(req->r->pool, 
  +	retval = ap_pstrcat(req->r->pool,
   			    retval ? retval : "",
   			    ((char **)values->elts)[i],
   			    (i == (values->nelts - 1)) ? NULL : ", ",
  @@ -249,7 +249,7 @@
   
   static void split_to_parms(ApacheRequest *req, const char *data)
   {
  -    request_rec *r = req->r; 
  +    request_rec *r = req->r;
       const char *val;
   
       while (*data && (val = my_urlword(r->pool, &data))) {
  @@ -274,22 +274,22 @@
           split_to_parms(req, r->args);
       }
   
  -    if (r->method_number == M_POST) { 
  -	const char *ct = ap_table_get(r->headers_in, "Content-type"); 
  -	if (ct && strcaseEQN(ct, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
  -	    result = ApacheRequest_parse_urlencoded(req); 
  +    if (r->method_number == M_POST) {
  +	const char *ct = ap_table_get(r->headers_in, "Content-type");
  +	if (ct && strncaseEQ(ct, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
  +	    result = ApacheRequest_parse_urlencoded(req);
   	}
  -	else if (ct && strcaseEQN(ct, MULTIPART_ENCTYPE, MULTIPART_ENCTYPE_LENGTH)) {
  -	   result = ApacheRequest_parse_multipart(req); 
  +	else if (ct && strncaseEQ(ct, MULTIPART_ENCTYPE, MULTIPART_ENCTYPE_LENGTH)) {
  +	   result = ApacheRequest_parse_multipart(req);
   	}
   	else {
  -	    ap_log_rerror(REQ_ERROR, 
  -			  "[libapreq] unknown content-type: `%s'", ct); 
  +	    ap_log_rerror(REQ_ERROR,
  +			  "[libapreq] unknown content-type: `%s'", ct);
   	    result = HTTP_INTERNAL_SERVER_ERROR;
   	}
  -    } 
  +    }
       else {
  -	result = ApacheRequest_parse_urlencoded(req); 
  +	result = ApacheRequest_parse_urlencoded(req);
       }
   
       req->parsed = 1;
  @@ -299,15 +299,15 @@
   
   int ApacheRequest_parse_urlencoded(ApacheRequest *req)
   {
  -    request_rec *r = req->r; 
  +    request_rec *r = req->r;
       int rc = OK;
   
  -    if (r->method_number == M_POST) { 
  +    if (r->method_number == M_POST) {
   	const char *data = NULL, *type;
   
   	type = ap_table_get(r->headers_in, "Content-Type");
   
  -	if (!strcaseEQN(type, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
  +	if (!strncaseEQ(type, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
   	    return DECLINED;
   	}
   	if ((rc = util_read(req, &data)) != OK) {
  @@ -327,10 +327,12 @@
   
       if( ap_pfclose(req->r->pool, upload->fp) )
   	ap_log_rerror(REQ_ERROR,
  -		      "[libapreq] close error on '%s'", upload->tempname);	
  +		      "[libapreq] close error on '%s'", upload->tempname);
  +#ifndef DEBUG
       if( remove(upload->tempname) )
   	ap_log_rerror(REQ_ERROR,
   		      "[libapreq] remove error on '%s'", upload->tempname);
  +#endif
   
       free(upload->tempname);
   }
  @@ -342,27 +344,26 @@
       char prefix[] = "apreq";
       char *name;
       int fd, tries = 100;
  -    
  +
       while (--tries > 0) {
   	if ( (name = tempnam(req->temp_dir, prefix)) == NULL )
   	    continue;
  -	fd = ap_popenf(r->pool, name, O_CREAT|O_EXCL|O_RDWR, 0600);
  +	fd = ap_popenf(r->pool, name, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600);
   	if ( fd >= 0 )
   	    break; /* success */
   	else
   	    free(name);
       }
  -    
  -    if ( tries == 0  || (fp = ap_pfdopen(r->pool, fd, "wb+") ) == NULL ) {
  -	ap_log_rerror(REQ_ERROR,
  -		      "[libapreq] could not open temp file '%s'", name); 	
  +
  +    if ( tries == 0  || (fp = ap_pfdopen(r->pool, fd, "w+" "b") ) == NULL ) {
  +	ap_log_rerror(REQ_ERROR, "[libapreq] could not create/open temp file");
   	if ( fd >= 0 ) { remove(name); free(name); }
   	return NULL;
       }
   
       upload->fp = fp;
       upload->tempname = name;
  -    ap_register_cleanup(r->pool, (void *)upload, 
  +    ap_register_cleanup(r->pool, (void *)upload,
   			remove_tmpfile, ap_null_cleanup);
       return fp;
   
  @@ -403,14 +404,14 @@
       }
   
       (void)ap_getword(r->pool, &ct, '=');
  -    boundary = ap_getword_conf(r->pool, &ct); 
  +    boundary = ap_getword_conf(r->pool, &ct);
   
       if (!(mbuff = multipart_buffer_new(boundary, length, r))) {
   	return DECLINED;
       }
   
       while (!multipart_buffer_eof(mbuff)) {
  -	table *header = multipart_buffer_headers(mbuff);	
  +	table *header = multipart_buffer_headers(mbuff);
   	const char *cd, *param=NULL, *filename=NULL;
   	char buff[FILLUNIT];
   	int blen, wlen;
  @@ -520,7 +521,7 @@
       if (*time_str == '-') {
   	is_neg = 1;
   	++time_str;
  -    } 
  +    }
       else if (*time_str == '+') {
   	++time_str;
       }
  @@ -538,7 +539,7 @@
       buf[ix] = '\0';
       offset = atoi(buf);
   
  -    return time(NULL) + 
  +    return time(NULL) +
   	(expire_mult(*time_str) * (is_neg ? (0 - offset) : offset));
   }
   
  @@ -558,13 +559,13 @@
   	return ap_pstrdup(p, time_str);
       }
   
  -    tms = gmtime(&when); 
  +    tms = gmtime(&when);
       return ap_psprintf(p,
  -		       "%s, %.2d%c%s%c%.2d %.2d:%.2d:%.2d GMT", 
  -		       ap_day_snames[tms->tm_wday], 
  +		       "%s, %.2d%c%s%c%.2d %.2d:%.2d:%.2d GMT",
  +		       ap_day_snames[tms->tm_wday],
   		       tms->tm_mday, sep, ap_month_snames[tms->tm_mon], sep,
  -		       tms->tm_year + 1900, 
  -		       tms->tm_hour, tms->tm_min, tms->tm_sec); 
  +		       tms->tm_year + 1900,
  +		       tms->tm_hour, tms->tm_min, tms->tm_sec);
   }
   
   char *ApacheRequest_expires(ApacheRequest *req, char *time_str)
  
  
  
  1.6       +7 -2      tcl-moddtcl/apache_request.h
  
  Index: apache_request.h
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/apache_request.h,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- apache_request.h	2001/06/04 09:54:46	1.5
  +++ apache_request.h	2001/06/21 17:47:10	1.6
  @@ -70,8 +70,8 @@
   #define strcaseEQ(s1,s2) (!strcasecmp(s1,s2))
   #endif
   
  -#ifndef strcaseEQN
  -#define strcaseEQN(s1,s2,n) (!strncasecmp(s1,s2,n))
  +#ifndef strncaseEQ
  +#define strncaseEQ(s1,s2,n) (!strncasecmp(s1,s2,n))
   #endif
   
   #define DEFAULT_TABLE_NELTS 10
  @@ -104,6 +104,11 @@
   
   #define ApacheRequest_upload(req) \
       ((req->parsed || (ApacheRequest_parse(req) == OK)) ? req->upload : NULL)
  +
  +
  +#define ApacheUpload_FILE(upload) (upload->fp)
  +
  +#define ApacheUpload_size(upload) (upload->size)
   
   #define ApacheUpload_info(upload, key) \
   ap_table_get(upload->info, key)
  
  
  
  1.32      +83 -63    tcl-moddtcl/mod_dtcl.c
  
  Index: mod_dtcl.c
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/mod_dtcl.c,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- mod_dtcl.c	2001/06/11 14:55:01	1.31
  +++ mod_dtcl.c	2001/06/21 17:47:10	1.32
  @@ -58,7 +58,7 @@
    * University of Illinois, Urbana-Champaign.
    */
   
  -/* $Id: mod_dtcl.c,v 1.31 2001/06/11 14:55:01 davidw Exp $  */
  +/* $Id: mod_dtcl.c,v 1.32 2001/06/21 17:47:10 davidw Exp $  */
   
   /* mod_dtcl.c by David Welton <da...@apache.org> - originally mod_include.  */
   /* See http://tcl.apache.org/mod_dtcl/credits.ttml for additional credits. */
  @@ -121,11 +121,21 @@
                                              dtcl_init_handler function */
   int cacheFreeSize = 0;           /* free space in cache */
   
  -static int upload_files_to_var = 0;
  +int upload_files_to_var = 0;
   
   static char *upload_dir = "/tmp/";      /* Upload directory */
   static unsigned int upload_max = 0;              /* Maximum amount of data that may be uploaded */
   
  +
  +/* eventually we will transfer 'global' variables in here and
  +   'de-globalize' them */
  +#if 0
  +typedef struct {
  +} dtcl_globals;
  +
  +dtcl_globals globals;
  +#endif
  +
   typedef struct {
       Tcl_Interp *server_interp;          /* per server Tcl interpreter */
       Tcl_Obj *dtcl_global_init_script;   /* run once when apache is first started */
  @@ -135,7 +145,7 @@
       Tcl_Obj *dtcl_after_script;         /*            after            */
       Tcl_Obj *dtcl_error_script;         /*            for errors */
       int dtcl_cache_size;
  -    char *server_name; 
  +    char *server_name;
   } dtcl_server_conf;
   
   #define GETREQINTERP(req) ((dtcl_server_conf *)ap_get_module_config(req->server->module_config, &dtcl_module))->server_interp
  @@ -185,8 +195,8 @@
   static int outputproc(ClientData instancedata, char *buf, int toWrite, int *errorCodePtr)
   {
       memwrite(&obuffer, buf, toWrite);
  -    return toWrite;		
  -} 
  +    return toWrite;
  +}
   
   static int closeproc(ClientData instancedata, Tcl_Interp *interp2)
   {
  @@ -291,7 +301,7 @@
   	} else {
   	    ap_rputs(errstr, r);
   	}
  -    }    
  +    }
       if (htmlflag != 1)
   	ap_rputs(ER2, r);
   
  @@ -334,26 +344,30 @@
   
   /* Function to be used should we desire to upload files to a variable */
   
  +#if 0
   int dtcl_upload_hook(void *ptr, char *buf, int len, ApacheUpload *upload)
   {
       Tcl_Interp *interp = ptr;
  -    static void *oldptr;
  -    int flag = 0;
  +    static int usenum = 0;
  +    static int uploaded = 0;
   
  -    /* if there is not a new file being added, keep adding it to the
  -       same list element.  Otherwise, start a new list element */
       if (oldptr != upload)
  -	flag = TCL_LIST_ELEMENT|TCL_APPEND_VALUE;
  -    else
  -	flag = TCL_APPEND_VALUE;
  +    {
  +    } else {
  +    }
   
  +#if USE_ONLY_UPLOAD_COMMAND == 0
  +
       Tcl_ObjSetVar2(interp,
   		   Tcl_NewStringObj("::request::UPLOAD", -1),
   		   Tcl_NewStringObj("data", -1),
  -		   Tcl_NewByteArrayObj(buf, len),
  -		   flag);
  +		   Tcl_DuplicateObj(uploadstorage[usenum]),
  +		   0);
  +#endif /* USE_ONLY_UPLOAD_COMMAND  */
       return len;
  -}  
  +}
  +#endif /* 0 */
  +
   
   /* Load, cache and eval a Tcl file  */
   
  @@ -368,18 +382,18 @@
          with the addition of caching code. */
       char *cmdBuffer = (char *) NULL;
       Tcl_Channel chan = Tcl_OpenFileChannel(interp, r->filename, "r", 0644);
  -    if (chan == (Tcl_Channel) NULL) 
  +    if (chan == (Tcl_Channel) NULL)
       {
   	Tcl_ResetResult(interp);
   	Tcl_AppendResult(interp, "couldn't read file \"", r->filename,
   			 "\": ", Tcl_PosixError(interp), (char *) NULL);
   	goto error;
       }
  -    
  +
       cmdBuffer = (char *) malloc(r->finfo.st_size + 1);
  -    
  +
       result = Tcl_Read(chan, cmdBuffer, r->finfo.st_size);
  -    if (result < 0) 
  +    if (result < 0)
       {
   	Tcl_Close(interp, chan);
   	Tcl_AppendResult(interp, "couldn't read file \"", r->filename,
  @@ -387,13 +401,13 @@
   	goto error;
       }
       cmdBuffer[result] = 0;
  -    
  -    if (Tcl_Close(interp, chan) != TCL_OK) 
  +
  +    if (Tcl_Close(interp, chan) != TCL_OK)
   	goto error;
  -    
  -    Tcl_SetStringObj(outbuf, cmdBuffer, strlen(cmdBuffer));   
  +
  +    Tcl_SetStringObj(outbuf, cmdBuffer, strlen(cmdBuffer));
       free(cmdBuffer);
  -        
  +
       /* yuck  */
       goto end;
   error:
  @@ -401,7 +415,7 @@
   	free(cmdBuffer);
       }
       return TCL_ERROR;
  -    
  +
   end:
       return TCL_OK;
   #else
  @@ -415,7 +429,7 @@
   {
       /* BEGIN PARSER  */
       char inside = 0;	/* are we inside the starting/ending delimiters  */
  -	
  +
       const char *strstart = STARTING_SEQUENCE;
       const char *strend = ENDING_SEQUENCE;
   
  @@ -455,7 +469,7 @@
   			     "Encountered error in mod_dtcl getchar routine while reading %s",
   			     r->uri);
   		ap_pfclose( r->pool, f);
  -	    }	    
  +	    }
   	c = ch;
   	if (!inside)
   	{
  @@ -470,7 +484,7 @@
   		    Tcl_AppendToObj(outbuf, "\"\n", 2);
   		    inside = 1;
   		    p = 0;
  -		    continue;			
  +		    continue;
   		} else {
   		    ungetc(nextchar, f);
   		}
  @@ -552,13 +566,14 @@
       {
   	Tcl_AppendToObj(outbuf, "\"\n", 2);
       }
  -	
  +
       if (toplevel)
       {
   	if (conf->dtcl_after_script)
   	    Tcl_AppendObjToObj(outbuf, conf->dtcl_after_script);
  -	    
  -	Tcl_AppendToObj(outbuf, "\n}\nnamespace delete request\n", -1);
  +
  +/* 	Tcl_AppendToObj(outbuf, "\n}\nnamespace delete request\n", -1); seems redundant */
  +	Tcl_AppendToObj(outbuf, "\n}\n", -1);
       }
       else
   	Tcl_AppendToObj(outbuf, "\n", -1);
  @@ -615,12 +630,13 @@
       char *hashKey = NULL;
       int isNew = 0;
       int result = 0;
  -       
  +
       Tcl_Obj *outbuf = NULL;
       Tcl_HashEntry *entry = NULL;
       Tcl_Interp *interp = GETREQINTERP(r);
  -       
  -    /* Look for the script's compiled version. If it's not found, create it. */
  +
  +    /* Look for the script's compiled version. If it's not found,
  +       create it. */
       if (cacheSize)
       {
   	hashKey = ap_psprintf(r->pool, "%s%ld%ld%d", r->filename, r->finfo.st_mtime, r->finfo.st_ctime, toplevel);
  @@ -632,10 +648,10 @@
   	Tcl_IncrRefCount(outbuf);
   
   	if(!strcmp(r->content_type, "application/x-httpd-tcl"))
  -	{ 
  +	{
   	    /* It's a TTML file  */
   	    result = get_ttml_file(r, interp, r->filename, 1, outbuf);
  -	} else { 	
  +	} else {
   	    /* It's a plain Tcl file */
   	    result = get_tcl_file(r, interp, r->filename, &(r->finfo), outbuf);
   	}
  @@ -656,7 +672,7 @@
   	    free(objCacheList[cacheSize - 1]);
   	    memmove(objCacheList + 1, objCacheList, sizeof(char *)*(cacheSize -1));
   	    objCacheList[0] = strdup(hashKey);
  -	} 
  +	}
       } else {
   	outbuf = (Tcl_Obj *)Tcl_GetHashValue(entry);
       }
  @@ -724,14 +740,16 @@
       /* Apache Request stuff */
       req = ApacheRequest_new(r);
       global_req = req;
  +#if 0
       if (upload_files_to_var)
       {
   	req->hook_data = interp;
  -	req->upload_hook = dtcl_upload_hook; 
  +	req->upload_hook = dtcl_upload_hook;
       }
  -    
  +#endif
  +
       ApacheRequest___parse(req);
  -    
  +
       /* take results and create tcl variables from them */
   #if USE_ONLY_VAR_COMMAND == 1
       if (req->parms)
  @@ -750,7 +768,7 @@
   		Tcl_Obj *newkey = STRING_TO_UTF_TO_OBJ(parms[i].key);
   		Tcl_Obj *newval = STRING_TO_UTF_TO_OBJ(parms[i].val);
   		Tcl_Obj *oldval = Tcl_ObjGetVar2(interp, varsobj, newkey, 0);
  -		
  +
   		if (oldval == NULL)
   		{
   		    Tcl_ObjSetVar2(interp, varsobj, newkey, newval, 0);
  @@ -762,11 +780,11 @@
   		}
   	    }
   	}
  -	
  +
       }
  -#endif 
  +#endif
  +#if USE_ONLY_UPLOAD_COMMAND == 1
       upload = req->upload;
  -
       /* Loop through uploaded files */
       while (upload)
       {
  @@ -815,9 +833,10 @@
   			       TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
   	    }
   	}
  -	
  +
   	upload = upload->next;
       }
  +#endif /* USE_ONLY_UPLOAD_COMMAND == 1 */
   
       get_parse_exec_file(r, 1);
       /* reset globals  */
  @@ -840,6 +859,7 @@
       Tcl_CreateObjCommand(interp, "headers", Headers, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
       Tcl_CreateObjCommand(interp, "hgetvars", HGetVars, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
       Tcl_CreateObjCommand(interp, "var", Var, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  +    Tcl_CreateObjCommand(interp, "upload", Upload, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
       Tcl_CreateObjCommand(interp, "include", Include, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
       Tcl_CreateObjCommand(interp, "parse", Parse, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
       Tcl_CreateObjCommand(interp, "hflush", HFlush, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
  @@ -858,13 +878,13 @@
       /* Initialize TCL stuff  */
   
       interp = Tcl_CreateInterp();
  -    dsc->server_interp = interp; /* root interpreter */    
  +    dsc->server_interp = interp; /* root interpreter */
   
       /* Create TCL commands to deal with Apache's BUFFs. */
       achan = Tcl_CreateChannel(&Achan, "apacheout", NULL, TCL_WRITABLE);
   
       system_encoding = Tcl_GetEncoding(NULL, "iso8859-1"); /* FIXME */
  -    
  +
       Tcl_SetStdChannel(achan, TCL_STDOUT);
       Tcl_SetChannelOption(interp, achan, "-buffering", "none");
   
  @@ -906,7 +926,7 @@
       }
   
       /* This is what happens if it is not set by the user */
  -    if(dsc->dtcl_cache_size < 0) 
  +    if(dsc->dtcl_cache_size < 0)
       {
   	if (ap_max_requests_per_child != 0)
   	    cacheSize = ap_max_requests_per_child / 2;
  @@ -934,7 +954,7 @@
   	    mydsc->server_interp = Tcl_CreateSlave(interp, sr->server_hostname, 0);
   	    tcl_create_commands(mydsc->server_interp);
   	    Tcl_SetChannelOption(mydsc->server_interp, achan, "-buffering", "none");
  -	    Tcl_RegisterChannel(mydsc->server_interp, achan);  
  +	    Tcl_RegisterChannel(mydsc->server_interp, achan);
   	}
   	mydsc->server_name = ap_pstrdup(p, sr->server_hostname);
   	sr = sr->next;
  @@ -961,7 +981,7 @@
   
       if (arg == NULL || arg2 == NULL)
   	return "Mod_Dtcl Error: Dtcl_Script requires two arguments";
  -   
  +
       objarg = Tcl_NewStringObj(arg2, -1);
       Tcl_IncrRefCount(objarg);
       Tcl_AppendToObj(objarg, "\n", 1);
  @@ -970,11 +990,11 @@
       } else if (strcmp(arg, "ChildInitScript") == 0) {
   	dsc->dtcl_child_init_script = objarg;
       } else if (strcmp(arg, "ChildExitScript") == 0) {
  -	dsc->dtcl_child_exit_script = objarg;      
  -    } else if (strcmp(arg, "BeforeScript") == 0) {       
  +	dsc->dtcl_child_exit_script = objarg;
  +    } else if (strcmp(arg, "BeforeScript") == 0) {
   	if (ddc == NULL)
  -	    dsc->dtcl_before_script = objarg; 
  -	else 
  +	    dsc->dtcl_before_script = objarg;
  +	else
   	    ddc->dtcl_before_script = objarg;
       } else if (strcmp(arg, "AfterScript") == 0) {
   	if (ddc == NULL)
  @@ -1026,14 +1046,14 @@
   
       dsc = (dtcl_server_conf *) ap_get_module_config(r->server->module_config, &dtcl_module);
   
  -    if (dconf != NULL) 
  +    if (dconf != NULL)
       {
   	newconfig = (dtcl_server_conf *) ap_pcalloc(r->pool, sizeof(dtcl_server_conf));
   	ddc = (dtcl_server_conf *) ap_get_module_config(dconf, &dtcl_module);
  -	newconfig->dtcl_before_script = ddc->dtcl_before_script ? ddc->dtcl_before_script : dsc->dtcl_before_script;	
  -	newconfig->dtcl_after_script = ddc->dtcl_after_script ? ddc->dtcl_after_script : dsc->dtcl_after_script;	
  +	newconfig->dtcl_before_script = ddc->dtcl_before_script ? ddc->dtcl_before_script : dsc->dtcl_before_script;
  +	newconfig->dtcl_after_script = ddc->dtcl_after_script ? ddc->dtcl_after_script : dsc->dtcl_after_script;
   	newconfig->dtcl_error_script = ddc->dtcl_error_script ? ddc->dtcl_error_script : dsc->dtcl_error_script;
  -		
  +
   	return newconfig;
       }
       return dsc;
  @@ -1071,9 +1091,9 @@
   #if 0 /* this stuff should only be done once at the top level  */
       dsc->dtcl_global_init_script = overrides->dtcl_global_init_script ? overrides->dtcl_global_init_script :	base->dtcl_global_init_script;
   
  -    dsc->dtcl_child_init_script = overrides->dtcl_child_init_script ? overrides->dtcl_child_init_script : base->dtcl_child_init_script;     
  +    dsc->dtcl_child_init_script = overrides->dtcl_child_init_script ? overrides->dtcl_child_init_script : base->dtcl_child_init_script;
   
  -    dsc->dtcl_child_exit_script = overrides->dtcl_child_exit_script ? overrides->dtcl_child_exit_script : base->dtcl_child_exit_script; 
  +    dsc->dtcl_child_exit_script = overrides->dtcl_child_exit_script ? overrides->dtcl_child_exit_script : base->dtcl_child_exit_script;
   
       dsc->dtcl_cache_size = overrides->dtcl_cache_size ? overrides->dtcl_cache_size : base->dtcl_cache_size;
   #endif
  @@ -1085,7 +1105,7 @@
       dsc->dtcl_error_script = overrides->dtcl_error_script ? overrides->dtcl_error_script : base->dtcl_error_script;
   
   
  -    dsc->server_name = overrides->server_name ? overrides->server_name : base->server_name; 
  +    dsc->server_name = overrides->server_name ? overrides->server_name : base->server_name;
   
       return dsc;
   }
  @@ -1101,7 +1121,7 @@
   
       sr = s;
       while(sr)
  -    {	
  +    {
   	dsc = (dtcl_server_conf *) ap_get_module_config(sr->module_config, &dtcl_module);
   	if (dsc->dtcl_child_init_script != NULL)
   	    if (Tcl_EvalObjEx(dsc->server_interp, dsc->dtcl_child_init_script, 0) != TCL_OK)
  
  
  
  1.6       +4 -0      tcl-moddtcl/mod_dtcl.h
  
  Index: mod_dtcl.h
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/mod_dtcl.h,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- mod_dtcl.h	2001/06/11 14:55:03	1.5
  +++ mod_dtcl.h	2001/06/21 17:47:11	1.6
  @@ -38,6 +38,10 @@
      'var' command. */
   #define USE_ONLY_VAR_COMMAND 0
   
  +/* Turn off 'old-style' $UPLOAD variable, and use only the 'upload'
  +   command.  */
  +#define USE_ONLY_UPLOAD_COMMAND 0
  +
   /* End Configuration options  */
   
   #define STARTING_SEQUENCE "<?"
  
  
  
  1.9       +179 -7    tcl-moddtcl/tcl_commands.c
  
  Index: tcl_commands.c
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/tcl_commands.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- tcl_commands.c	2001/06/11 14:55:04	1.8
  +++ tcl_commands.c	2001/06/21 17:47:12	1.9
  @@ -16,6 +16,7 @@
   #include "apache_cookie.h"
   #include "mod_dtcl.h"
   
  +#define BUFSZ 4096
   
   extern request_rec *global_rr;
   extern obuff obuffer;
  @@ -23,6 +24,8 @@
   extern int buffer_output;
   extern int headers_printed;
   extern int cacheFreeSize;
  +extern int upload_files_to_var;
  +extern Tcl_Obj *uploadstorage[];
   
   extern ApacheRequest *global_req;
   
  @@ -63,7 +66,7 @@
   {
       Tcl_Channel fd;
       int sz;
  -    char buf[2000];
  +    char buf[BUFSZ];
   
       if (objc != 2)
       {
  @@ -81,8 +84,8 @@
   	Tcl_SetChannelOption(interp, fd, "-translation", "lf");
       }
   /*     print_headers(global_rr);
  -    flush_output_buffer(global_rr);  */
  -    while ((sz = Tcl_Read(fd, buf, sizeof(buf) - 1)))
  +       flush_output_buffer(global_rr);  */
  +    while ((sz = Tcl_Read(fd, buf, BUFSZ - 1)))
       {
   	if (sz == -1)
   	{
  @@ -96,7 +99,7 @@
              it, depending on buffering */
   	memwrite(&obuffer, buf, sz);
   
  -	if (sz < sizeof(buf) - 1)
  +	if (sz < BUFSZ - 1)
   	    break;
       }
       return Tcl_Close(interp,fd);
  @@ -372,7 +375,7 @@
   	Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("USER_NAME", -1), STRING_TO_UTF_TO_OBJ(ap_pstrdup(global_rr->pool, pw->pw_name)), 0);
       else
   	Tcl_ObjSetVar2(interp, EnvsObj, Tcl_NewStringObj("USER_NAME", -1),
  -		    STRING_TO_UTF_TO_OBJ(ap_psprintf(global_rr->pool, "user#%lu", (unsigned long) global_rr->finfo.st_uid)), 0);
  +		       STRING_TO_UTF_TO_OBJ(ap_psprintf(global_rr->pool, "user#%lu", (unsigned long) global_rr->finfo.st_uid)), 0);
   #endif
   
       if ((t = strrchr(global_rr->filename, '/')))
  @@ -454,7 +457,7 @@
   	Tcl_WrongNumArgs(interp, 1, objv, "(get varname|list varname|exists varname|names|number|all)");
   	return TCL_ERROR;
       }
  -    command = Tcl_GetStringFromObj(objv[1], NULL);
  +    command = Tcl_GetString(objv[1]);
   
       if (!strcmp(command, "get"))
       {
  @@ -603,6 +606,175 @@
       return TCL_OK;
   }
   
  +/*
  +upload get XYZ
  +               channel        # returns channel
  +	       save (name)    # returns name?
  +	       data           # returns data
  +
  +with the third one reporting an error if this hasn't been enabled, or
  +the first two if it has.
  +
  +upload info XYZ
  +
  +                exists
  +                size
  +                type
  +                filename
  +
  +upload names
  +
  +gets all the upload names.
  +*/
  +
  +int Upload(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
  +{
  +    char *command = NULL;
  +    Tcl_Obj *result = NULL;
  +    ApacheUpload *upload;
  +
  +    if (objc < 2 || objc > 5)
  +    {
  +	Tcl_WrongNumArgs(interp, 1, objv, "get ...|info ...|names");
  +	return TCL_ERROR;
  +    }
  +    command = Tcl_GetString(objv[1]);
  +
  +    if (!strcmp(command, "get"))
  +    {
  +	char *varname = NULL;
  +	if (objc < 4)
  +	{
  +	    Tcl_WrongNumArgs(interp, 2, objv, "varname channel|save filename|var varname");
  +	    return TCL_ERROR;
  +	}
  +	varname = Tcl_GetString(objv[2]);
  +	upload = ApacheUpload_find(global_req->upload, varname);
  +	if (upload != NULL) /* make sure we have an upload */
  +	{
  +	    Tcl_Channel chan;
  +	    char *method = Tcl_GetString(objv[3]);
  +	    if (!strcmp(method, "channel"))
  +	    {
  +		if (ApacheUpload_FILE(upload) != NULL)
  +		{
  +		    /* create and return a file channel */
  +		    char *channelname = NULL;
  +		    chan = Tcl_MakeFileChannel((ClientData *)fileno(
  +			ApacheUpload_FILE(upload)), TCL_READABLE);
  +		    Tcl_RegisterChannel(interp, chan);
  +		    channelname = Tcl_GetChannelName(chan);
  +		    result = Tcl_NewStringObj(channelname, -1);
  +		}
  +	    } else if (!strcmp(method, "save")) {
  +		/* save data to a specified filename  */
  +
  +		int sz;
  +		char savebuffer[BUFSZ];
  +		Tcl_Channel savechan = NULL;
  +		Tcl_Channel chan = NULL;
  +		if (objc != 5)
  +		{
  +		    Tcl_WrongNumArgs(interp, 4, objv, "filename");
  +		    return TCL_ERROR;
  +		}
  +
  +		savechan = Tcl_OpenFileChannel(interp, Tcl_GetString(objv[4]), "w", 0600);
  +		if (savechan == NULL)
  +		    return TCL_ERROR;
  +		else
  +		    Tcl_SetChannelOption(interp, savechan, "-translation", "binary");
  +
  +		chan = Tcl_MakeFileChannel((ClientData *)fileno(
  +		    ApacheUpload_FILE(upload)), TCL_READABLE);
  +		Tcl_SetChannelOption(interp, chan, "-translation", "binary");
  +
  +		while ((sz = Tcl_Read(chan, savebuffer, BUFSZ)))
  +		{
  +		    if (sz == -1)
  +		    {
  +			Tcl_AddErrorInfo(interp, Tcl_PosixError(interp));
  +			return TCL_ERROR;
  +		    }
  +
  +		    Tcl_Write(savechan, savebuffer, sz);
  +		    if (sz < 4096)
  +			break;
  +		}
  +		Tcl_Close(interp, savechan);
  +		result = Tcl_NewIntObj(1);
  +	    } else if (!strcmp(method, "data")) {
  +		/* this sucks - we should use the hook, but I want to
  +                   get everything fixed and working first */
  +		if (upload_files_to_var)
  +		{
  +		    char *bytes = NULL;
  +		    Tcl_Channel chan = NULL;
  +
  +		    bytes = Tcl_Alloc(ApacheUpload_size(upload));
  +		    chan = Tcl_MakeFileChannel((ClientData *)fileno(
  +			ApacheUpload_FILE(upload)), TCL_READABLE);
  +		    Tcl_SetChannelOption(interp, chan, "-translation", "binary");
  +		    Tcl_SetChannelOption(interp, chan, "-encoding", "binary");
  +		    /* put data in a variable  */
  +		    result = Tcl_NewObj();
  +		    Tcl_ReadChars(chan, result, ApacheUpload_size(upload), 0);
  +		} else {
  +		    Tcl_AppendResult(interp, "Dtcl_UploadFilesToVar is not set", NULL);
  +		    return TCL_ERROR;
  +		}
  +	    }
  +	    Tcl_SetObjResult(interp, result);
  +	} else {
  +	    /* no variable found  */
  +	    Tcl_SetObjResult(interp, Tcl_NewStringObj("", -1));
  +	}
  +    } else if (!strcmp(command, "info")) {
  +	char *varname = NULL;
  +	char *infotype = NULL;
  +	if (objc != 4)
  +	{
  +	    Tcl_WrongNumArgs(interp, 2, objv, "varname exists|size|type|filename");
  +	    return TCL_ERROR;
  +	}
  +	varname = Tcl_GetString(objv[2]);
  +	infotype = Tcl_GetString(objv[3]);
  +
  +	upload = ApacheUpload_find(global_req->upload, varname);
  +	if (upload != NULL)
  +	{
  +	    if (!strcmp(infotype, "exists"))
  +	    {
  +		result = Tcl_NewIntObj(1);
  +	    } else if (!strcmp(infotype, "size")) {
  +		result = Tcl_NewIntObj(ApacheUpload_size(upload));
  +	    } else if (!strcmp(infotype, "type")) {
  +		char *type = NULL;
  +		type = (char *)ApacheUpload_type(upload);
  +		if (type)
  +		    result = Tcl_NewStringObj(type, -1);
  +		else
  +		    result = Tcl_NewStringObj("", -1);
  +	    } else if (!strcmp(infotype, "filename")) {
  +		result = Tcl_NewStringObj(upload->filename, -1);
  +	    } else {
  +		Tcl_AddErrorInfo(interp, "unknown upload info command");
  +		return TCL_ERROR;
  +	    }
  +	} else {
  +	    if (!strcmp(infotype, "exists")) {
  +		result = Tcl_NewIntObj(0);
  +	    } else {
  +		Tcl_AddErrorInfo(interp, "variable doesn't exist");
  +		return TCL_ERROR;
  +	    }
  +	}
  +	Tcl_SetObjResult(interp, result);
  +    }
  +    return TCL_OK;
  +}
  +
  +
   /* Tcl command to get, and print some information about the current
      state of affairs */
   
  @@ -612,7 +784,7 @@
       tble = ap_psprintf(global_rr->pool,
   		       "<table border=0 bgcolor=green><tr><td>\n"
   		       "<table border=0 bgcolor=\"#000000\">\n"
  -		       "<tr><td align=center bgcolor=blue><font color=\"#ffffff\" size=+2>dtcl_info</font><br></td></tr>\n"
  +		       "<tr><td align=center bgcolor=blue><font color=\"#ffffff\" size=\"+2\">dtcl_info</font><br></td></tr>\n"
   		       "<tr><td><font color=\"#ffffff\">Free cache size: %d</font><br></td></tr>\n"
   		       "<tr><td><font color=\"#ffffff\">PID: %d</font><br></td></tr>\n"
   		       "</table>\n"
  
  
  
  1.4       +2 -0      tcl-moddtcl/tcl_commands.h
  
  Index: tcl_commands.h
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/tcl_commands.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- tcl_commands.h	2001/05/21 19:49:22	1.3
  +++ tcl_commands.h	2001/06/21 17:47:12	1.4
  @@ -17,6 +17,8 @@
   
   int Var(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
   
  +int Upload(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  +
   int Dtcl_Info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
   
   int No_Body(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  
  
  
  1.4       +1 -231    tcl-moddtcl/docs/documentation.txt
  
  Index: documentation.txt
  ===================================================================
  RCS file: /home/cvs/tcl-moddtcl/docs/documentation.txt,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- documentation.txt	2001/05/03 11:49:09	1.3
  +++ documentation.txt	2001/06/21 17:47:17	1.4
  @@ -1,233 +1,3 @@
   
  -mod_dtcl Documentation
  +   
   
  -  1) Installation
  -  
  -    1. Check dependencies
  -       To install mod_dtcl, you will need Tcl 8.2 or greater and Apache
  -       1.3.xx. It is known to run on Linux, FreeBSD, OpenBSD, and Solaris
  -       and HPUX. NT is also possible - please see the directions in the
  -       distribution.
  -    2. Get mod_dtcl
  -       If you are running a Debian or FreeBSD system, there are pre-built
  -       packages available at:
  -       [1]http://www.debian.org/Packages/unstable/web/libapache-mod-dtcl.
  -       html or [2]http://www.freebsd.org/ports/www.html#mod_dtcl-0.8.1.1.
  -       Otherwise, download the sources at
  -       [3]http://tcl.apache.org/mod_dtcl/download/.
  -    3. Uncompress the sources
  -       gunzip apache-1.3.X.tar.gz
  -       tar -xvf apache-1.3.X.tar.gz
  -       You don't need the Apache sources if you are building a shared
  -       object module. You do, however, need the header files. Some
  -       systems, such as Debian GNU/Linux, provide these independently -
  -       otherwise, you probably still need the sources.
  -       gunzip mod_dtcl-X.X.X.tar.gz
  -       tar -xvf mod_dtcl-X.X.X.tar.gz
  -    4. Configuring, builddtcl.sh, etc...
  -       Do you want to build mod_dtcl as a shared object (such as a .so
  -       file on Linux, or a .dll on windows), or compile it directly as a
  -       part of the Apache executable? The Apache Software Foundation has
  -       put together a nice [4]manual which explains things in detail.
  -          + For shared objects
  -            cd ../mod_dtcl/
  -            Edit the builddtcl.sh script. The 3 variables you may need to
  -            change are:
  -               o TCLSH
  -                 Name of the tclsh program on your computer.
  -               o APACHE
  -                 Location of the Apache sources (for static builds only).
  -               o INC
  -                 Location of the Apache headers (you will need this even
  -                 for building shared objects).
  -            ./builddtcl.sh shared
  -            cp mod_dtcl.so
  -            /usr/lib/apache/wherever/the/other/shared/objects/reside For
  -            shared object builds, you need to copy the object into the
  -            directory where the other shared objects are kept for your
  -            Apache build. On Debian GNU/Linux systems, for instance, this
  -            is in /usr/lib/apache/1.3/.
  -          + For static builds
  -            cd apache-1.3.X/
  -            ./configure
  -            cd ../mod_dtcl/
  -            Edit the builddtcl.sh script. The 3 variables you may need to
  -            change are:
  -               o TCLSH
  -                 Name of the tclsh program on your computer.
  -               o APACHE
  -                 Location of the Apache sources (for static builds only).
  -               o INC
  -                 Location of the Apache headers (you will need this even
  -                 for building shared objects).
  -            ./builddtcl.sh static
  -            ./builddtcl.sh install
  -            cd ../apache-1.3.X
  -            ./configure --activate-module=src/modules/mod_dtcl/mod_dtcl.a
  -            [ other configure options ]
  -            export EXTRA_LIBS="-ltcl8.X -lm"
  -            make -e
  -            make install
  -    5. Configure Apache
  -          + http.conf
  -            LoadModule dtcl_module /usr/lib/apache/1.3/mod_dtcl.so
  -            This points Apache to the shared object if mod_dtcl is being
  -            used as a loadable module.
  -          + srm.conf
  -            AddType application/x-httpd-tcl .ttml
  -            AddType application/x-dtcl-tcl .tcl (optional)
  -            These add the .ttml and .tcl (if desired) types to Apache, so
  -            that they are processed by mod_dtcl.
  -       
  -  2) Apache Directives
  -  
  -     * Dtcl_Script GlobalInitScript "script"
  -       Tcl script that is run when each interpreter is initialized.
  -       "script" is actual Tcl script, so to run a file, you would do
  -       Dtcl_Script GlobalInitScript "source /var/www/foobar.tcl".
  -     * Dtcl_Script ChildInitScript "script"
  -       Script to be evaluated when each apache child is initialized. This
  -       is the best place to load modules.
  -     * Dtcl_Script ChildExitScript "script"
  -       Script to be evaluated when each apache child exits.
  -     * Dtcl_Script BeforeScript "script"
  -       Script to be evaluated before each .ttml page. Note that you
  -       cannot use hputs in the BeforeScript, but must instead use
  -       buffer_add.
  -     * Dtcl_Script AfterScript "script"
  -       Script to be called after each .ttml page.
  -     * Dtcl_Script ErrorScript "script"
  -       This code is called in place of the standard 'error' pages
  -       generated for mod_dtcl. This directive may be useful if you have
  -       sensitive logic that you wish to protect.
  -     * Dtcl_CacheSize cachesize
  -       Number of ttml scripts to cache as Tcl Objects. Default is
  -       MaxRequestsPerChild / 2, or 50, if MaxRequestsPerChild is 0.
  -     * Dtcl_UploadFilesToVar 1/0
  -       If set to 1, files will be uploaded to the variable UPLOAD(data).
  -       Be careful with this, as large files could use up your memory.
  -       
  -  3) mod_dtcl specific Tcl commands and variables
  -  
  -     * buffer_add string
  -       Add text to output_buffer for later printing. Used internally.
  -     * hputs ?-error? text
  -       The mod_dtcl version of "puts". Outputs to the client, instead of
  -       to stdout. The error option permits you to send an 'error message'
  -       to the apache log file, at the NOTICE level.
  -     * hgetvars
  -       Get environmental, CGI and Cookie variables. This is in a seperate
  -       command so as not to make the server do this every time you load a
  -       .ttml file. ENVS, VARS, and COOKIES are the associative arrays
  -       created. ENVS contains environmental variables, VARS contains all
  -       the 'cgi' variables, and COOKIES, any cookies recieved from the
  -       client.
  -     * include filename
  -       Include a file without parsing it. This is the best way to include
  -       an HTML file or any other static content.
  -     * parse filename
  -       "Source" a .ttml file. This is the way to include other .ttml
  -       files.
  -     * hflush
  -       Flush the output buffers to the client. Use this if you want to
  -       incrementally update a page.
  -     * headers redirect uri
  -       Redirect from the current page to a new URI. Must be done in the
  -       first block of TCL code.
  -     * headers setcookie -name cookie-name -value cookie-value ?-expires
  -       date/time? ?-domain domain? ?-path path? ?-secure?
  -       This command is for setting cookies. Cookie-name is the name of
  -       the cookie, cookie-value is the data associated with the variable.
  -       Expires sets an expiration date for the cookie, and must be in the
  -       format 'DD-Mon-YY HH:MM:SS', path sets the path for which the
  -       cookie is valid, and secure specifies that the cookie is only to
  -       be transmitted if the connection is secure (HTTPS).
  -     * headers type content-type
  -       This command sets the "Content-type:" header returned by the
  -       script, which is useful if you wish to create a PNG (image), for
  -       example, with mod_dtcl.
  -     * headers set headername value
  -       Set arbitrary header names and values.
  -     * dtcl_info
  -       Prints information on the internals of the module in HTML.
  -       Currently, only the PID and size of the object cache are reported.
  -     * Note that these variables may be lists if more than one file is
  -       uploaded at a time.
  -       $::request::UPLOAD(filename)
  -       The filename of the uploaded file.
  -       $::request::UPLOAD(name)
  -       The form variable name of the upload.
  -       $::request::UPLOAD(size)
  -       The size of the uploaded file.
  -       $::request::UPLOAD(type)
  -       The content type of the file upload. Not always available!
  -       $::request::UPLOAD(channelname)
  -       The name of a Tcl channel which may be used to manipulate the
  -       uploaded file. If Dtcl_UploadFilesToVar is set, this variable
  -       doesn't get created. If no file is passed to the server, this
  -       variable does not exist! Be sure to check for this.
  -       $::request::UPLOAD(data)
  -       Contents of the uploaded file, if Dtcl_UploadFilesToVar is set.
  -       
  -  4) Internals
  -  
  -     * Read the code!
  -     * Initialization
  -       When Apache is started, (or when child Apache processes are
  -       started if a threaded Tcl is used), tcl_init_stuff is called,
  -       which creates a new interpreter, and initializes various things,
  -       like the apache_channel channel system. The caching system is also
  -       set up, and if there is a GlobalScript, it is run.
  -     * Achan/apache_channel
  -       The "Apache Channel" system was created so that it is possible to
  -       have an actual Tcl channel that we could redirect standard output
  -       to. This lets us use, for instance, the regular "puts" command in
  -       .ttml pages. It works by creating commands that write to memory
  -       that is slated to be sent to the client.
  -     * Page parsing/execution
  -       In send_parsed_file Each .ttml file is loaded and run within its
  -       own namespace. No new interpreter is created for each page. This
  -       lets you share variables, and most importantly, loaded modules,
  -       from a common parent (such as one of the InitScripts). When a file
  -       is loaded, it is transformed into a Tcl script by putting
  -       everything outside of <? and ?> into large hputs statements. When
  -       the script is complete, it is then inserted into the cache, for
  -       future use. In fact, if the file modification information doesn't
  -       change, mod_dtcl will execute the cached version of the script the
  -       next time it is encountered.
  -     * Binary data
  -       mod_dtcl is capable of outputing binary data, such as images, or
  -       loading binary data with 'include'.
  -       
  -  5) Upgrading From Older (< 0.9.3) Versions
  -  
  -     * New tags
  -       As of version 0.9.4, mod_dtcl uses <? and ?> instead of <+ and +>
  -       to delimit sections of Tcl code. By default, dtcl is still
  -       compiled with code to parse the <? ?> tags, but it will run faster
  -       if USE_OLD_TAGS is set to 0 in mod_dtcl.h. You can automatically
  -       change your .ttml files to the new format by using the newtags.sh
  -       script in the contrib/ directory. Run it at the top level of your
  -       DocumentRoot.
  -     * headers setcookie
  -       The headers setcookie command now uses the -name and -value flags
  -       for those arguments, whereas this was not necessary in the past.
  -       
  -  6) Getting Help
  -  
  -     * Mailing list
  -       The mod_dtcl mailing list is the best place to go for help when
  -       you have problems.
  -       See the [5]Contact page for information on sending
  -       mail/subscribing.
  -       Mailing list archives are also available at
  -       [6]http://archive.covalent.net, at the bottom of the page.
  -
  -References
  -
  -   1. http://www.debian.org/Packages/unstable/web/libapache-mod-dtcl.html
  -   2. http://www.freebsd.org/ports/www.html#mod_dtcl-0.8.1.1
  -   3. file://localhost/home/davidw/workshop/tcl-moddtcl/docs/download/
  -   4. http://httpd.apache.org/docs/dso.html
  -   5. http://tcl.apache.org/mod_dtcl/contact.ttml
  -   6. http://archive.covalent.net/