aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorswhite <swhite@61ea717e-8e0c-4c3c-b38e-e9c67f54f1f1>2004-04-19 13:10:13 +0000
committerswhite <swhite@61ea717e-8e0c-4c3c-b38e-e9c67f54f1f1>2004-04-19 13:10:13 +0000
commitb55bae51688e9d97c6848b0a5e073dcc8851723f (patch)
tree2845f8afcfde0bccdba07b3f7ec0f1021705ad2a
parent2cb1df63dcc158674fd15cae88e0939e683aec6f (diff)
Addresses Cactus bug 923
Made the download list to be organized by variable, then by data output type, then by slice. To facilitate list manipulation, added temporarily a list module 'PtrList', which perhaps may prove of more general use in the future. Pursuant to Cactus bug 907 Added parameter HTTPExtra::viewport_refresh_seconds to send Refresh header to web browser. Made ViewPort window to respond to viewport_refresh_seconds parameter General HTML improvements...checked with Amaya and lynx. Re-organized CSS info in HTTPD web pages. Got rid of httpuMimeType code which didn't do anything. git-svn-id: http://svn.cactuscode.org/arrangements/CactusConnect/HTTPDExtra/trunk@54 61ea717e-8e0c-4c3c-b38e-e9c67f54f1f1
-rw-r--r--param.ccl8
-rw-r--r--src/Groups.c11
-rw-r--r--src/HTTPD_FileList.c64
-rw-r--r--src/HTTPD_FileList.h62
-rw-r--r--src/HostNames.c4
-rw-r--r--src/IO.c480
-rw-r--r--src/PtrList.c656
-rw-r--r--src/PtrList.h53
-rw-r--r--src/PtrList.txt249
-rw-r--r--src/PtrList_Namespace.h37
-rw-r--r--src/make.code.defn2
11 files changed, 1407 insertions, 219 deletions
diff --git a/param.ccl b/param.ccl
index 97a8074..c3de3b3 100644
--- a/param.ccl
+++ b/param.ccl
@@ -1,2 +1,10 @@
# Parameter definitions for thorn httpd_utils
# $Header$
+
+private:
+
+INT viewport_refresh_seconds "Viewport web page refresh time seconds" STEERABLE = ALWAYS
+{
+ -1: :: "-1 for no refresh, 0 for immediate refresh"
+} -1
+
diff --git a/src/Groups.c b/src/Groups.c
index eb5af1d..08325e1 100644
--- a/src/Groups.c
+++ b/src/Groups.c
@@ -8,7 +8,6 @@
@version $Id$
@@*/
-#include <stdlib.h>
#include <string.h>
#include "cctk.h"
@@ -74,9 +73,9 @@ int HTTPUTILS_RegisterPages (void)
static int MessagesPage (const cGH *GH, httpRequest *request, void *data)
{
int retval = 0;
- char currtime[64], currdate[64];
+ char currtime[64] = EMPTYSTRING, currdate[64] = EMPTYSTRING;
String *message = String_New();
- const char *temp, *name, *memo;
+ const char *temp;
static char *message_board = NULL;
@@ -85,8 +84,8 @@ static int MessagesPage (const cGH *GH, httpRequest *request, void *data)
if (HTTP_Num_Arguments( request ) > 0)
{
- name = HTTP_ArgumentValue (request, "name");
- memo = HTTP_ArgumentValue (request, "memo");
+ const char *name = HTTP_ArgumentValue (request, "name");
+ const char *memo = HTTP_ArgumentValue (request, "memo");
if (name && *name && memo && *memo)
{
@@ -173,7 +172,7 @@ static int MessagesPage (const cGH *GH, httpRequest *request, void *data)
"<tr><td valign=\"top\">Message:</td><td>"
"<textarea name=\"memo\" rows=\"10\" cols=\"40\"></textarea>\n"
"</td></tr></table>\n"
- "<input type=\"submit\" value=\"Submit Message\" />\n"
+ "<p>\n<input type=\"submit\" value=\"Submit Message\" />\n</p>\n"
"<table width=\"80%\"><tr><td>\n"
"<h2>Messages:</h2></td></tr>\n"
"<tr><td><table width=\"100%\" cellpadding=\"5\" cellspacing=\"5\">"
diff --git a/src/HTTPD_FileList.c b/src/HTTPD_FileList.c
new file mode 100644
index 0000000..fbc4a87
--- /dev/null
+++ b/src/HTTPD_FileList.c
@@ -0,0 +1,64 @@
+#include "HTTPD_FileList.h"
+#include "PtrList.h"
+
+/* wrapper functions to make PtrList type-safe for FileList items */
+
+size_t
+HTTPD_FileList_NumberOfItems( const FileList * list )
+{
+ return List_NumberOfItems( list );
+}
+
+FileList *
+HTTPD_FileList_New()
+{
+ return (FileList *)List_New();
+}
+
+void
+HTTPD_FileList_Delete( FileList * list )
+{
+ List_Delete( list );
+}
+
+void
+HTTPD_FileList_FreeItemsInListAndEmpty( FileList * list )
+{
+ List_FreeItemsInListAndEmpty( list );
+}
+
+void
+HTTPD_FileList_Append( FileList * list, httpFileItem * item )
+{
+ List_Append( list, item );
+}
+
+httpFileItem *
+HTTPD_FileList_Item( const FileList * list, size_t index )
+{
+ return List_Item( list, index );
+}
+
+void
+HTTPD_FileList_SortAccordingTo( FileList * list,
+ HTTPD_FileListSortComparison comparison )
+{
+ List_SortAccordingTo( list, (ListSortComparison)comparison );
+}
+
+int
+HTTPD_FileListCompare_Var_Thorn_Slice(
+ const httpFileItem * a, const httpFileItem * b )
+{
+ int order = Compare( a->varname, b->varname );
+ if( order == 0 )
+ {
+ order = Compare( a->thorn, b->thorn );
+ if( order == 0 )
+ return Compare( a->slice, b->slice );
+ else
+ return order;
+ }
+ else
+ return order;
+}
diff --git a/src/HTTPD_FileList.h b/src/HTTPD_FileList.h
new file mode 100644
index 0000000..fc3e5fc
--- /dev/null
+++ b/src/HTTPD_FileList.h
@@ -0,0 +1,62 @@
+#ifndef _HTTPDFILELIST_H_
+#define _HTTPDFILELIST_H_ 1
+
+/* SW temporary explicit paths while testing SString module */
+#include "CactusConnect/HTTPD/src/SString.h"
+#include "CactusConnect/HTTPD/src/SString_Namespace.h"
+
+typedef struct httpFileItem_tag
+{
+ const String *thorn;
+ const String *varname;
+ const String *mimetype;
+ const String *slice;
+ const String *description;
+ const String *filename;
+ const String *linkname;
+} httpFileItem;
+
+typedef enum {FLFALSE, FLTRUE} FLBOOL;
+
+/* a wrapper module around PtrList for type safety */
+
+typedef struct PtrList_tag FileList;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+size_t HTTPD_FileList_NumberOfItems( const FileList * );
+FileList * HTTPD_FileList_New( void );
+void HTTPD_FileList_Delete( FileList * );
+
+void HTTPD_FileList_FreeItemsInListAndEmpty( FileList * );
+void HTTPD_FileList_Append( FileList *, httpFileItem * item );
+httpFileItem * HTTPD_FileList_Item( const FileList *, size_t index );
+
+typedef int (*HTTPD_FileListSortComparison)( const httpFileItem *,
+ const httpFileItem * );
+int HTTPD_FileListCompare_Var_Thorn_Slice( const httpFileItem *,
+ const httpFileItem * );
+
+void HTTPD_FileList_SortAccordingTo( FileList *, HTTPD_FileListSortComparison comparison );
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#define NumberOfFiles( a ) \
+ HTTPD_FileList_NumberOfItems( a )
+#define FileItem( a, b ) \
+ HTTPD_FileList_Item( a, b )
+#define AppendFile( a, b ) \
+ HTTPD_FileList_Append( a, b )
+#define SortFilesAccordingTo( a, b ) \
+ HTTPD_FileList_SortAccordingTo( a, b )
+#define FreeFileItemsInListAndEmpty( a ) \
+ HTTPD_FileList_FreeItemsInListAndEmpty( a )
+#define Variable_Thorn_Slice \
+ HTTPD_FileListCompare_Var_Thorn_Slice
+#endif
diff --git a/src/HostNames.c b/src/HostNames.c
index 1099883..132dd0a 100644
--- a/src/HostNames.c
+++ b/src/HostNames.c
@@ -13,10 +13,6 @@
#include "util_Network.h"
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
diff --git a/src/IO.c b/src/IO.c
index 2ff0df1..575f6d3 100644
--- a/src/IO.c
+++ b/src/IO.c
@@ -9,31 +9,24 @@
@@*/
#include "cctk.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include "cctk_Parameters.h"
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include "util_String.h"
-
#include "CactusBase/IOUtil/src/ioutil_AdvertisedFiles.h"
#include "http_Content.h"
-/* SW Temporary, while testing the SString module*/
-#include "CactusConnect/HTTPD/src/SString.h"
+#include "HTTPD_FileList.h"
+
+/* SW Temporary, while testing the SString module */
#include "CactusConnect/HTTPD/src/SString_Namespace.h"
static const char *rcsid = "$Header$";
-CCTK_FILEVERSION(CactusConnect_HTTPDExtra_IO_c)
-
+CCTK_FILEVERSION(CactusConnect_HTTPDExtra_IO_c);
/********************************************************************
******************** Macro Definitions ************************
@@ -42,24 +35,9 @@ CCTK_FILEVERSION(CactusConnect_HTTPDExtra_IO_c)
#define O_BINARY 0
#endif
-
/********************************************************************
********************* Internal Typedefs **********************
********************************************************************/
-struct httpuFileList
-{
- struct httpuFileList *next;
- char *filename;
- char *linkname;
- ioAdvertisedFileDesc data;
-};
-
-struct httpuMimeType
-{
- struct httpuMimeType *next;
- const char *name;
-};
-
/********************************************************************
******************** Internal Routines ************************
@@ -80,9 +58,7 @@ int HTTP_util_RegisterIOPages(void);
/********************************************************************
********************* Local Data *****************************
********************************************************************/
-static struct httpuFileList *filelist = NULL;
-static struct httpuMimeType *mimetypes = NULL;
-
+static FileList *filelist = NULL;
/*@@
@routine HTTP_util_RegisterIOPages
@@ -106,20 +82,20 @@ int HTTP_util_RegisterIOPages(void)
listener.advertise = IOFileListener;
- IOUtil_RegisterAdvertisedFileListener (NULL, CCTK_THORNSTRING,
+ IOUtil_RegisterAdvertisedFileListener ( NULL, CCTK_THORNSTRING,
&listener);
- HTTP_RegisterPage("/Output/index.html", AdvertisedFilePage, NULL);
- HTTP_RegisterPage("/Output/viewport.html", ViewportFilePage, NULL);
+ HTTP_RegisterPage( "/Output/index.html", AdvertisedFilePage, NULL);
+ HTTP_RegisterPage( "/Output/viewport.html", ViewportFilePage, NULL);
- HTTP_ContentLink("/Output/index.html", "Files",
+ HTTP_ContentLink( "/Output/index.html", "Files",
"Downloadable files",
HTTP_QUICKLINK);
- HTTP_ContentLink("/Output/viewport.html", "Viewport",
+ HTTP_ContentLink( "/Output/viewport.html", "Viewport",
"Viewport for certain output files",
HTTP_QUICKLINK);
- HTTP_RegisterPage("/Output", SendFilePage, NULL);
+ HTTP_RegisterPage( "/Output", SendFilePage, NULL);
return 0;
}
@@ -139,66 +115,115 @@ int HTTP_util_RegisterIOPages(void)
static int IOFileListener(const cGH *GH, const char *filename,
const ioAdvertisedFileDesc *description)
{
- struct httpuFileList *entry;
- struct httpuMimeType *type;
- char *position;
+ size_t position = 0;
+ httpFileItem *entry = (httpFileItem *)malloc( sizeof( httpFileItem));
- /* avoid compiler warning about unused parameter */
- (void) (GH + 0);
-
- entry = (struct httpuFileList *)malloc(sizeof(struct httpuFileList));
+ (void) (GH + 0); /* avoid compiler warning about unused parameter */
if(entry)
{
- entry->next = NULL;
- entry->filename = Util_Strdup(filename);
- entry->linkname = Util_Strdup(filename);
- entry->data.thorn = Util_Strdup(description->thorn);
- entry->data.varname = Util_Strdup(description->varname);
- entry->data.mimetype = Util_Strdup(description->mimetype);
- entry->data.slice = Util_Strdup(description->slice);
- entry->data.description = Util_Strdup(description->description);
-
- entry->next = filelist;
- filelist = entry;
+/* SW--HEY where does this all get deleted ? */
+ String *linknameString = String_Make( filename);
+ entry->thorn = String_Make( description->thorn);
+ entry->varname = String_Make( description->varname);
+ entry->mimetype = String_Make( description->mimetype);
+ entry->slice = String_Make( description->slice);
+ entry->description = String_Make( description->description);
+ entry->filename = String_Make( filename);
+ entry->linkname = linknameString;
+
+ if( filelist == NULL )
+ filelist = HTTPD_FileList_New();
+ AppendFile( filelist, entry );
/* Need to mangle the filename to get a decent linkname */
- for(position=entry->linkname; *position;position++)
+ while( FindCharFrom( linknameString, '/', &position ) )
+ SetNthChar( linknameString, position, '@');
+ }
+
+ return 0;
+}
+
+static void
+IndentAndConcatCString( String *message, const char *c, int depth )
+{
+ int i;
+ for ( i = 0; i < depth; i++ )
+ ConcatCString( message, "\t" );
+ ConcatCString( message, c );
+}
+/*
+ * SW
+ * Build a HTML representation of the contents of filelist.
+ * Denis wanted variable name on the topmost level.
+ * This is about third iteration. Here, use tables to get nesting effect.
+ */
+static size_t
+buildList( const FileList *list, String * message, size_t itemNo, int depth )
+{
+ const size_t n = NumberOfFiles( filelist );
+ size_t i = 0;
+ httpFileItem *lastItem = FileItem( filelist, itemNo );
+
+ for ( i = itemNo; i < n; i++ )
+ {
+ httpFileItem *file = FileItem( filelist, i );
+ if( depth == 0 )
{
- if(*position == '/')
- {
- *position = '@';
- }
+ IndentAndConcatCString( message, "<tr>", depth );
+ ConcatCString( message, "<td colspan=\"5\" class=\"variable\">" );
+ Concat( message, file->varname );
+ ConcatCString( message, "&nbsp;" );
+ IndentAndConcatCString( message, "</td></tr>\n", depth );
+ i = buildList( list, message, i, 1 );
}
-
- for(type=mimetypes; type; type=type->next)
+ if( depth == 1 )
{
- if(!strcmp(type->name,entry->data.mimetype))
+ if( Equals( file->varname, lastItem->varname ) )
{
- break;
+ IndentAndConcatCString( message, "<tr>", depth );
+ ConcatCString( message, "<td class=\"spacer\">&nbsp;</td>"
+ "<td class=\"thorn\" colspan=\"4\">" );
+ Concat( message, file->thorn );
+ IndentAndConcatCString( message, "</td></tr>\n", depth );
+ i = buildList( list, message, i, 2 );
}
+ else
+ break;
}
-
- /* Keep a list of mimetypes too. */
- if(!type)
+ if( depth == 2 )
{
- type = (struct httpuMimeType *)malloc(sizeof(struct httpuMimeType));
-
- if(type)
+ if( Equals( file->thorn, lastItem->thorn )
+ && Equals( file->varname, lastItem->varname ) )
{
- type->name = Util_Strdup(description->mimetype);
-
- type->next = mimetypes;
- mimetypes = type;
+ IndentAndConcatCString( message, "<tr>", depth );
+ ConcatCString( message, "<td class=\"spacer\">&nbsp;</td>"
+ "<td class=\"spacer\">&nbsp;</td>\n"
+ "<td class=\"slice\">" );
+ Concat( message, file->slice );
+
+ ConcatCString( message, "\n" );
+ IndentAndConcatCString( message, "</td><td class=\"link\">\n", depth );
+ IndentAndConcatCString( message, "<a href=\"/Output/", depth );
+ Concat( message, file->linkname );
+ ConcatCString( message, "\">" );
+ Concat( message, file->filename );
+ ConcatCString( message, "</a>\n" );
+ IndentAndConcatCString( message, "</td><td class=\"desc\">\n", depth );
+ IndentAndConcatCString( message, "", depth );
+ Concat( message, file->description );
+ ConcatCString( message, "\n" );
+ IndentAndConcatCString( message, "</td></tr>\n", depth );
}
+ else
+ break;
}
}
-
- return 0;
+ ConcatCString( message, "\n" );
+ return i - 1;
}
-
/*@@
@routine AdvertisedFilePage
@date Sun Sep 17 18:26:01 2000
@@ -211,74 +236,85 @@ static int AdvertisedFilePage(const cGH *GH, httpRequest *request, void *data)
{
int retval = 0;
String *message = String_New();
- struct httpuFileList *list;
data = data; /* avoid compiler warning about unused parameter */
HTTP_Send_OK_Header( request );
HTTP_SetDoctype( message );
- HTTP_SendString(request, message);
- /* Start the page */
- HTTP_Send(request, "<html><head>\n" );
- HTTP_Send(request, "<title>Cactus Downloadable Files</title>\n");
+ HTTP_SendString( request, message);
+
+ HTTP_Send( request, "<html><head>\n" );
+ HTTP_Send( request, "<title>Cactus Downloadable Files</title>\n");
HTTP_SetHeadInfo( message);
- HTTP_SendString(request, message );
+ HTTP_Send( request, "<style type=\"text/css\">"
+ "\t.files td { text-align: left; font-family: sans-serif;\n"
+ "\t padding-left: 1ex; padding-right: 1ex; }\n"
+ "\t.files td.variable { background-color: #ff9;\n"
+ "\t font-weight: bold; }\n"
+ "\t.files td.thorn { background-color: #dff;\n"
+ "\t color: black; }\n"
+ "\t.files td.slice { background-color: #fde;\n"
+ "\t font-family: monospace; }\n"
+ "\t.files td.link { \n"
+ " }\n"
+ "\t.files td.desc { background-color: #dff;\n"
+ "\t font-style: italic; }\n"
+ "\t#filescaption { border-bottom: thin black solid;\n"
+ "\t margin-bottom: 1em; }\n"
+ "\t</style>\n");
+ HTTP_SendString( request, message );
- HTTP_Send(request, "</head>\n<body>\n");
+ HTTP_Send( request, "</head>\n<body>\n");
- /* HTTP_Write out the header part. */
- HTTP_SetContentHeaderString(GH, 0, message, NULL);
- HTTP_SendString(request, message);
+ HTTP_SetContentHeaderString( GH, 0, message, NULL);
+ HTTP_SendString( request, message);
- HTTP_Send(request, "<h1>Downloadable Files</h1>");
+ HTTP_Send( request, "<h1>Downloadable Files</h1>\n");
- HTTP_Send(request,
+ HTTP_Send( request,
"<p>From this page you can download various output files \n"
"from the simulation. Depending on the software available on your\n"
- " local machine, you can change the browser properties to launch\n"
- " files directly to visualization clients.</p> \n "
- "<p>Some of these output files can be directly viewed on \n"
- "a browser on the simulation \n"
- "<a href=\"/Output/viewport.html\">viewport</a></p>\n"
- "<p>Many IO methods have <i>steerable</i> parameters which \n"
- "allow you to e.g. add fields and customise behaviour.\n"
- "Depending on your authorisation, you can access the \n"
- "<a href=\"/Parameters/index.html\">parameter steering page</a></p>\n"
+ " local machine, you can change the browser properties to launch\n"
+ " files directly to visualization clients.</p> \n "
+ "<p>Some of these output files can be directly viewed on \n"
+ "a browser on the simulation \n"
+ "<a href=\"/Output/viewport.html\">viewport</a></p>\n"
+ "<p>Many IO methods have <dfn>steerable</dfn> parameters which \n"
+ "allow you to e.g. add fields and customise behaviour.\n"
+ "Depending on your authorisation, you can access the \n"
+ "<a href=\"/Parameters/index.html\">parameter steering page</a>"
+ "</p>\n");
+ HTTP_Send( request,
"<div class=\"centered\">\n"
- "<table cellspacing=\"5\" cellpadding=\"5\" rules=\"cols\">\n"
- "<thead>\n"
- "<tr><th>File Name</th><th>Variable</th><th>Description</th></tr>\n"
- "</thead>\n<tbody>\n");
+ "<table class=\"files\" id=\"filescaption\" "
+ "frame=\"below\" cellpadding=\"0\" cellspacing=\"0\">\n"
+ "<tr><td class=\"variable\">\n"
+ "Variable</td><td class=\"thorn\">Thorn</td>\n"
+ "<td class=\"slice\"> Slice</td><td class=\"file\"> File</td>\n"
+ "<td class=\"desc\"> Description</td></tr>\n</table>\n"
+ "\n"
+ );
- for (list = filelist; list; list = list->next)
- {
- SetToCString(message, "<tr><td valign=\"top\"><a href=\"/Output/" );
- ConcatCString(message, list->linkname );
- ConcatCString(message, "\">" );
- ConcatCString(message, list->filename );
- ConcatCString(message, "</a></td>" );
- ConcatCString(message, "<td valign=\"top\">" );
- ConcatCString(message, list->data.varname );
- ConcatCString(message, "</td><td valign=\"top\">" );
- ConcatCString(message, list->data.description );
- ConcatCString(message, "</td></tr>\n" );
-
- HTTP_SendString(request, message);
- }
+ Truncate( message, 0 );
+ SortFilesAccordingTo( filelist, Variable_Thorn_Slice );
- HTTP_Send(request,"</tbody></table>\n</div>");
+ HTTP_Send( request, "<table cellpadding=\"0\" cellspacing=\"0\""
+ " class=\"files\">\n");
+ buildList( filelist, message, 0, 0 );
- /* Write out the footer part. */
- HTTP_SetContentFooterString(GH, 0, message);
- retval = HTTP_SendString(request, message);
+ HTTP_SendString( request, message);
+ HTTP_Send( request, "\n</table>");
+ HTTP_Send( request, "\n</div>");
+
+ HTTP_SetContentFooterString( GH, 0, message);
+ retval = HTTP_SendString( request, message);
String_Delete( message );
return retval;
}
-
/*@@
@routine SendFilePage
@date Sun Sep 17 18:43:40 2000
@@ -287,66 +323,71 @@ static int AdvertisedFilePage(const cGH *GH, httpRequest *request, void *data)
Sends an advertised file.
@enddesc
@@*/
-static int SendFilePage(const cGH *GH, httpRequest *request, void *data)
+
+static int SendFilePage( const cGH *GH, httpRequest *request, void *data)
{
- struct httpuFileList *list;
+ int found = 0;
+ const size_t n = NumberOfFiles( filelist );
+ size_t i;
/* avoid compiler warning about unused parameters */
(void) (GH + 0);
data = data;
- for (list = filelist; list; list = list->next)
+ for( i = 0; i < n; i++ )
{
- if(!strcmp(list->linkname, HTTP_Residual( request ) ))
+ httpFileItem *file = FileItem( filelist, i );
+
+ if( !CompareCString( file->linkname, HTTP_Residual( request ) ))
{
- int filedes;
- if((filedes = open(list->filename, O_RDONLY | O_BINARY)) >= 0)
+ int filedes = open( GetBuffer( file->filename), O_RDONLY | O_BINARY);
+ if(filedes >= 0)
{
- HTTP_Send(request, "HTTP/1.0 200 OK\r\n");
+ HTTP_Send( request, "HTTP/1.0 200 OK\r\n");
- HTTP_Send(request, "Content-Type: " );
- HTTP_Send(request, list->data.mimetype);
- HTTP_Send(request, "\r\n\r\n" );
+ HTTP_Send( request, "Content-Type: " );
+ HTTP_SendString( request, file->mimetype);
+ HTTP_Send( request, "\r\n\r\n" );
- HTTP_ContentSendFromFile(request, filedes);
+ HTTP_ContentSendFromFile( request, filedes);
- close(filedes);
+ close( filedes);
+ found = 1;
}
else
{
- HTTP_Send(request,"HTTP/1.0 500 Server Internal Error\r\n");
-
- HTTP_Send(request, "Content-Type: text/html\r\n\r\n");
- HTTP_Send(request, "<html>\n<head>\n");
- HTTP_Send(request, "<title>Error 500: Internal Error</title>\n");
- HTTP_Send(request, "</head>\n<body>\n");
- HTTP_Send(request, "<div class=\"centered\"><p>Unable to open " );
- HTTP_Send(request, list->filename );
- HTTP_Send(request, "</p></div>\n");
- HTTP_Send(request, "</body>\n</html>\n" );
+ HTTP_Send( request,"HTTP/1.0 500 Server Internal Error\r\n");
+
+ HTTP_Send( request, "Content-Type: text/html\r\n\r\n");
+ HTTP_Send( request, "<html>\n<head>\n");
+ HTTP_Send( request, "<title>Error 500: Internal Error</title>\n");
+ HTTP_Send( request, "</head>\n<body>\n");
+ HTTP_Send( request, "<div class=\"centered\"><p>Unable to open " );
+ HTTP_SendString( request, file->filename );
+ HTTP_Send( request, "</p></div>\n");
+ HTTP_Send( request, "</body>\n</html>\n" );
}
break;
}
}
- if(!list)
+ if(!found)
{
- HTTP_Send(request,"HTTP/1.0 404 Not Found\r\n");
+ HTTP_Send( request,"HTTP/1.0 404 Not Found\r\n");
- HTTP_Send(request,"Content-Type: text/html\r\n\r\n");
+ HTTP_Send( request,"Content-Type: text/html\r\n\r\n");
- HTTP_Send(request, "<html>\n<head>\n" );
- HTTP_Send(request, "<title>Error 404: Not Found</title>\n" );
- HTTP_Send(request, "</head>\n<body>\n" );
- HTTP_Send(request, "<div class=\"centered\"><p>" );
- HTTP_Send(request, HTTP_URI( request ) );
- HTTP_Send(request, " does not exist</p></div>\n" );
- HTTP_Send(request, "</body>\n</html>\n" );
+ HTTP_Send( request, "<html>\n<head>\n" );
+ HTTP_Send( request, "<title>Error 404: Not Found</title>\n" );
+ HTTP_Send( request, "</head>\n<body>\n" );
+ HTTP_Send( request, "<div class=\"centered\"><p>" );
+ HTTP_Send( request, HTTP_URI( request ) );
+ HTTP_Send( request, " does not exist</p></div>\n" );
+ HTTP_Send( request, "</body>\n</html>\n" );
}
return 0;
}
-
/*@@
@routine AdvertisedFilePage
@date Sun Sep 17 18:26:01 2000
@@ -355,39 +396,58 @@ static int SendFilePage(const cGH *GH, httpRequest *request, void *data)
Page to deal with advertised files.
@enddesc
@@*/
+
static int ViewportFilePage(const cGH *GH, httpRequest *request, void *data)
{
+ DECLARE_CCTK_PARAMETERS
+
int retval = 0;
int foundone = 0;
String *message = String_New();
- struct httpuFileList *list;
+ const size_t n = NumberOfFiles( filelist );
+ size_t i;
- /* avoid compiler warning about unused parameters */
(void) (GH + 0);
- data = data;
+ data = data; /* avoid compiler warning about unused parameters */
- HTTP_Send_OK_Header( request );
+ HTTP_Send_OK_Refresh_Header( request, viewport_refresh_seconds );
HTTP_SetDoctype( message );
- HTTP_SendString(request, message);
+ HTTP_SendString( request, message);
- /* Start the page */
- HTTP_Send(request, "<html>\n<head>\n");
- HTTP_Send(request, "<title>Cactus Downloadable Files</title>\n");
+ HTTP_Send( request, "<html>\n<head>\n");
+ HTTP_Send( request, "<title>Cactus Downloadable Files</title>\n");
HTTP_SetHeadInfo( message);
- HTTP_SendString(request, message );
-
- HTTP_Send(request, "</head>\n<body>\n");
- /* HTTP_Write out the header part. */
-
- HTTP_SetContentHeaderString(GH, 0, message, NULL);
- HTTP_SendString(request, message);
-
- HTTP_Send(request, "<h1>Viewport</h1>\n");
-
- HTTP_Send(request,
+ HTTP_Send( request, "<style type=\"text/css\">"
+ ".files td { text-align: center; vertical-align: middle;"
+ " font-size: smaller; font-family: sans-serif; }\n"
+ ".files .spacer { width: 10ex;\n"
+ " }\n"
+ ".files .variable { background-color: #ff9;\n"
+ " font-weight: bold; }\n"
+ ".files .thorn { background-color: #dff;\n"
+ " color: black; }\n"
+ ".files .slice { background-color: #fde;\n"
+ " font-family: monospace; }\n"
+ ".files .link { }\n"
+ ".files .desc { font-style: italic;\n"
+ " background-color: #dff; }\n"
+ ".files img { border: 0;\n"
+ " }\n"
+ "</style>\n");
+
+ HTTP_SendString( request, message );
+
+ HTTP_Send( request, "</head>\n<body>\n");
+
+ HTTP_SetContentHeaderString( GH, 0, message, NULL);
+ HTTP_SendString( request, message);
+
+ HTTP_Send( request, "<h1>Viewport</h1>\n");
+
+ HTTP_Send( request,
"<p>This page displays certain types of the output files \n"
"from the <a href=\"/Output/index.html\">download</a> page \n"
"as images (currently only JPEGs [mime type image/jpeg]).</p>\n"
@@ -397,57 +457,61 @@ static int ViewportFilePage(const cGH *GH, httpRequest *request, void *data)
"<a href=\"/Parameters/index.html\">parameter steering page</a></p>\n"
"<div class=\"centered\">\n");
- for (list = filelist; list; list = list->next)
+ SortFilesAccordingTo( filelist, Variable_Thorn_Slice );
+
+ for ( i = 0; i < n; i++ )
{
- if (CCTK_Equals(list->data.mimetype,"image/jpeg"))
+ httpFileItem *file = FileItem( filelist, i );
+ if ( !CompareCString( file->mimetype, "image/jpeg"))
{
if (!foundone)
{
- HTTP_Send(request,
- "<table cellspacing=\"5\" cellpadding=\"5\">\n"
- "<tr><th>Variable<br>File Name</th>\n"
- "<th>Description</th><th>Image</th></tr>\n");
+ HTTP_Send( request,
+ "<table class=\"files\" cellspacing=\"5\" cellpadding=\"5\" "
+ "rules=\"groups\" >\n"
+ "<thead>\n<tr><th>Variable<br />Slice</th>"
+ "<th>Description</th><th>Image</th></tr>\n</thead>\n");
foundone = 1;
}
- HTTP_Send(request, "<tr>\n" );
- HTTP_Send(request, "<td valign=center><small>" );
- HTTP_Send(request, list->data.varname );
- HTTP_Send(request, "<br />\n" );
- HTTP_Send(request, "<a href=\"/Output/" );
- HTTP_Send(request, list->linkname );
- HTTP_Send(request, "\">" );
- HTTP_Send(request, list->filename );
- HTTP_Send(request, "</a>\n" );
- HTTP_Send(request, "</small></td>\n" );
- HTTP_Send(request, "<td valign=center>" );
- HTTP_Send(request, list->data.description );
- HTTP_Send(request, "</td>\n" );
- HTTP_Send(request, "<td valign=center><a href=\"/Output/" );
- HTTP_Send(request, list->linkname );
- HTTP_Send(request, "\">" );
- HTTP_Send(request, "<img border=\"0\" width=\"100\" height=\"100\" src=\"" );
- HTTP_Send(request, list->linkname );
- HTTP_Send(request, "\" />" );
- HTTP_Send(request, "</a></td>\n" );
- HTTP_Send(request, "</tr>\n" );
+ HTTP_Send( request, "<tr>\n" );
+ HTTP_Send( request, "<td><span class=\"variable\">" );
+ HTTP_SendString( request, file->varname );
+ HTTP_Send( request, "</span><br />\n" );
+ HTTP_Send( request, "<span class=\"slice\">" );
+ HTTP_SendString( request, file->slice );
+ HTTP_Send( request, "</span>" );
+ HTTP_Send( request, "</td>\n" );
+ HTTP_Send( request, "<td><span class=\"desc\">" );
+ HTTP_SendString( request, file->description );
+ HTTP_Send( request, "</span></td>\n" );
+ HTTP_Send( request, "<td class=\"linkk\"><a href=\"/Output/" );
+ HTTP_SendString( request, file->linkname );
+ HTTP_Send( request, "\">" );
+ HTTP_Send( request, "<img width=\"100\" height=\"100\" src=\"" );
+ HTTP_SendString( request, file->linkname );
+ HTTP_Send( request, "\" alt=\"" );
+ HTTP_SendString( request, file->linkname );
+ HTTP_Send( request, "\"/>" );
+ HTTP_Send( request, "</a></td>\n" );
+ HTTP_Send( request, "</tr>\n" );
}
}
- if (!foundone)
+ if( foundone)
+ HTTP_Send( request, "</table>\n");
+ else
{
- HTTP_Send(request, "<strong>\n<p>No viewable images registered!</p>\n"
+ HTTP_Send( request, "<strong>\n<p>No viewable images registered!</p>\n"
"</strong>\n");
}
+ HTTP_Send( request, "</div>\n");
- HTTP_Send(request, "</div>\n");
-
- /* Write out the footer part. */
-
- HTTP_SetContentFooterString(GH, 0, message);
- retval = HTTP_SendString(request, message);
+ HTTP_SetContentFooterString( GH, 0, message);
+ retval = HTTP_SendString( request, message);
String_Delete( message );
+
return retval;
}
diff --git a/src/PtrList.c b/src/PtrList.c
new file mode 100644
index 0000000..d15acc9
--- /dev/null
+++ b/src/PtrList.c
@@ -0,0 +1,656 @@
+#include "PtrList.h"
+#include <stdlib.h>
+#include <memory.h>
+
+#ifdef macintosh
+#include <string.h>
+#endif
+
+#define ITEMSONFULLPAGE 62
+#define TAKEDEFAULTSIZE 0
+#define MIN(a,b) (a<b?a:b)
+
+typedef struct ListPage_tag ListPage;
+
+typedef struct PtrList_tag
+{
+ ListPage *firstPage;
+ size_t itemsPerPage;
+} PtrList_PLACEHOLDER;
+
+/* ===========================================================================
+ * ____________________________ ListPage _____________________________________
+ * For efficiency, the pointers in the list are arranged into blocks,
+ * called ListPage's.
+ * ======================================================================== */
+
+typedef struct ListPage_tag
+{
+ size_t numberOfItems;
+ size_t maxItems;
+ ListPage * next;
+ void * *items;
+} ListPage_PLACEHOLDER;
+
+static ListPage *
+ListPage_New( size_t maxItems )
+{
+ ListPage *new = (ListPage *)calloc( 1, sizeof( ListPage ) );
+ if( new )
+ {
+ new->items = malloc( maxItems * sizeof( void * ) );
+ new->maxItems = maxItems;
+ }
+ return new;
+}
+
+#define ListPage_IsFull( page ) \
+ ( ((const ListPage *)page)->numberOfItems >= page->maxItems )
+
+
+static ListPage *
+ListPage_Dup( const ListPage * other );
+
+static void *
+ListPage_Append( ListPage * this, void * item );
+
+static void *
+ListPage_RemoveItem( ListPage * this, size_t index );
+
+static void *
+ListPage_InsertItem( ListPage * this, size_t index, void * item );
+
+ /* ListPage_Dup does not copy the next pointer */
+ListPage *
+ListPage_Dup( const ListPage * other )
+{
+ ListPage * this = ListPage_New( other->maxItems );
+ if( other->numberOfItems > 0 )
+ memcpy( this->items, other->items,
+ other->numberOfItems * sizeof( void * ) );
+
+ this->maxItems = other->maxItems;
+ this->numberOfItems = other->numberOfItems;
+
+ return this;
+}
+
+ /* Returns the input pointer if it doesn't fit on page
+ * (for similarity with InsertItem) */
+void *
+ListPage_Append( ListPage *this, void * item )
+{
+ if( this->numberOfItems < this->maxItems ) /* If page not full */
+ {
+ *( this->items + this->numberOfItems ) = item; /* item to end*/
+ this->numberOfItems++; /* Update number of items on page */
+ return NULL;
+ }
+ return item;
+}
+
+ /* Returns a pointer to the item removed, or NULL if no item found */
+void *
+ListPage_RemoveItem( ListPage *this, size_t index )
+{
+ if( index < this->numberOfItems )
+ {
+ const size_t lastItemToShift = this->numberOfItems - 1;
+ size_t i;
+ void *item = *( this->items + index );
+
+ this->numberOfItems--;
+
+ for( i = index; i < lastItemToShift; i++ )
+ *( this->items + i ) = *( this->items + i + 1 );
+
+ return item;
+ }
+ return NULL;
+}
+
+ /* Returns a pointer to any item bumped off the page due to
+ * the page being full. (could be the input item) */
+void *
+ListPage_InsertItem( ListPage *this, size_t index, void * item )
+{
+ void * remainder = NULL;
+
+ if( index < this->numberOfItems )
+ {
+ const size_t firstItemToShift = this->numberOfItems - 1;
+ size_t i;
+
+ if( this->numberOfItems >= this->maxItems )
+ remainder = *( this->items + firstItemToShift );
+
+ this->numberOfItems = MIN( this->numberOfItems + 1,
+ this->maxItems );
+
+ for( i = firstItemToShift; i > index; i-- )
+ *( this->items + i ) = *( this->items + i - 1 );
+
+ *( this->items + index ) = item;
+ }
+ else
+ remainder = ListPage_Append( this, item );
+
+ return remainder;
+}
+
+/* ===========================================================================
+ ______________________________ PtrList functions _________________________
+
+ ======================================================================== */
+
+static void
+List_HandleAddressingError()
+{
+ /* To taste */
+}
+
+static ListPage * List_Xerox( const PtrList *other);
+static void List_FindItemAddress( const PtrList *this, size_t itemNo,
+ ListPage ** thePage, size_t *thePageIndex );
+
+ /*_____________________________________________________________________
+ **Constructor & Destructor**__________________________________________
+ *_____________________________________________________________________
+ */
+
+PtrList *
+List_New( void )
+{
+ return List_NewWithPageSize( TAKEDEFAULTSIZE );
+}
+
+PtrList *
+List_NewWithPageSize( size_t itemsOnFullPage )
+{
+ PtrList *new = (PtrList *)calloc( 1, sizeof( PtrList ) );
+ if( new )
+ {
+ if( itemsOnFullPage == TAKEDEFAULTSIZE )
+ new->itemsPerPage = ITEMSONFULLPAGE;
+ else
+ new->itemsPerPage = itemsOnFullPage;
+ }
+ return new;
+}
+
+PtrList *
+List_MakeCopy( const PtrList *other )
+{
+ PtrList *this = (PtrList *)calloc( 1, sizeof( PtrList ) );
+ this->itemsPerPage = other->itemsPerPage;
+ this->firstPage = List_Xerox( other );
+ return this;
+}
+
+void
+List_Delete( PtrList *list )
+{
+ List_Empty( list );
+ free( list );
+}
+
+ /*_____________________________________________________________________
+ **Empty**____________________________________________________________
+ * Runs through the list of ListPages deleting the (previous) page.
+ *_____________________________________________________________________
+ */
+void
+List_Empty( PtrList * this )
+{
+ if( this->firstPage != NULL )
+ {
+ ListPage *prevPage = this->firstPage,
+ *startPage = this->firstPage->next;
+ ListPage *page;
+
+ this->firstPage = NULL; /* Prefer to do this first,
+ so list is consistent */
+ for( page = startPage; page != NULL; page = page->next )
+ {
+ free( prevPage );
+ prevPage = page;
+ }
+ free( prevPage );
+ }
+}
+ /*_____________________________________________________________________
+ **NumberOfItems**______________________________________________________
+ * Runs through the list of ListPages totalling the items on each page.
+ * -> This number could be cached.
+ *______________________________________________________________________
+ */
+size_t
+List_NumberOfItems( const PtrList *this )
+{
+ size_t number = 0;
+ ListPage *page;
+
+ for( page = this->firstPage; page != NULL; page = page->next )
+ number += page->numberOfItems;
+
+ return number;
+}
+ /*_____________________________________________________________________
+ **Append**_____________________________________________________________
+ * This and Insert the only PtrList method that allocates ListPages.
+ * If there are no pages with space on them, it allocates an new
+ * page and links the page the the previous last page.
+ * If there is space on the page, it adds the item to the end of
+ * the page and updates the number of items on the page.
+ *______________________________________________________________________
+ */
+void
+List_Append( PtrList *this, void * newItem )
+{
+ ListPage *page;
+
+ if( this->firstPage == NULL ) /* Add first page if necessary*/
+ this->firstPage = ListPage_New( this->itemsPerPage );
+
+ page = this->firstPage;
+
+ while( page != NULL ) /* Cycle through pages */
+ { /* Try to put on page*/
+ if( ListPage_Append( page, newItem ) == NULL )
+ return; /* Go home with a smile */
+ else if( page->next == NULL ) /* If next page doesn't exist*/
+ page->next = ListPage_New( this->itemsPerPage );
+ /* make new page and */
+ /* link to this*/
+
+ page = page->next; /* Try the next page*/
+ }
+ List_HandleAddressingError();
+}
+
+ /*_____________________________________________________________________
+ * Internal routine for List_Insert.
+ * Assumes check has already been done for item address and that
+ * it exists on the given page.
+ *
+ * It is inserted on the page. The question is, what to do if the
+ * page was almost empty, and an item had to be bumped off the page
+ * to accomodate it.
+ *
+ * Could shift all elemtents in the list up by one. Might be
+ * expensive
+ *
+ * Strategey here will be to add a new page after the present one
+ * if the next page is either full or non-existant. That way, only
+ * elements on the next page are affected, and if another item is
+ * added to the present page (as often happens) very little more work
+ * need be done.
+ *______________________________________________________________________
+ */
+static void
+List_InsertExistingItem( PtrList *list, ListPage *page, size_t pageIndex,
+ void *item )
+{
+ void * remnant = ListPage_InsertItem( page, pageIndex, item );
+ if( remnant ) /* An item got bumped off when inserting into page */
+ {
+ ListPage *next = page->next;
+ if( next == NULL || ListPage_IsFull( next ) )
+ {
+ ListPage *new = ListPage_New( list->itemsPerPage );
+ ListPage_Append( new, item ); /* Item on new */
+ new->next = next; /* link new page */
+ page->next = new;
+ }
+ else
+ ListPage_InsertItem( next, 0, remnant );
+ }
+}
+ /*_____________________________________________________________________
+ **List_Insert**
+ * Inserts the item at the specified index, shifting indices of
+ * existing list items as necessary. If index equals the number
+ * of items in the list less one, the item is appended to the list.
+ *______________________________________________________________________
+ */
+
+void
+List_Insert( PtrList * list, size_t index, void * item )
+{
+ if( index >= List_NumberOfItems( list ) )
+ List_Append( list, item );
+ else
+ {
+ ListPage *page = NULL;
+ size_t pageIndex;
+
+ List_FindItemAddress( list, index, &page, &pageIndex );
+
+ if( page != NULL )
+ List_InsertExistingItem( list, page, pageIndex, item );
+ else
+ List_HandleAddressingError();
+ /* probably should handle an addressing error */
+ }
+}
+
+ /*_____________________________________________________________________
+ **Item**_______________________________________________________________
+ * Returns the item of given index; returns NULL if no such index.
+ *______________________________________________________________________
+ */
+
+void *
+List_Item( const PtrList *this, size_t requestedIndex )
+{
+ ListPage *itsPage = NULL;
+ size_t itsPageIndex;
+
+ List_FindItemAddress( this, requestedIndex, &itsPage, &itsPageIndex );
+
+ if( itsPage != NULL )
+ return *( itsPage->items + itsPageIndex );
+
+ return NULL;
+}
+ /*_____________________________________________________________________
+ **SetItem**____________________________________________________________
+ * Sets the item of given index. Calls user-supplied addressing
+ * handler if no such item exists.
+ *______________________________________________________________________
+ */
+void
+List_SetItem( PtrList *this, size_t requestedIndex, void *value )
+{
+ ListPage *itsPage = NULL;
+ size_t itsPageIndex;
+
+ List_FindItemAddress( this, requestedIndex, &itsPage, &itsPageIndex );
+
+ if( itsPage != NULL )
+ *( itsPage->items + itsPageIndex ) = value;
+ else
+ List_HandleAddressingError();
+}
+
+ /*_____________________________________________________________________
+ **CopyList**_________________________________________________________
+ * Empties this list and puts items from other list in it.
+ *______________________________________________________________________
+ */
+void
+List_CopyList( PtrList * this, const PtrList * other )
+{
+ List_Empty( this );
+ this->itemsPerPage = other->itemsPerPage;
+ this->firstPage = List_Xerox( other );
+}
+ /*_____________________________________________________________________
+ **RemoveItem**_________________________________________________________
+ * Removes the item of given index from the list by shifting all the
+ * following items back by one and reducing itsNumberOfItems by one.
+ * -> It would kind of be nice if this also deleted empty pages
+ *______________________________________________________________________
+ */
+void *
+List_RemoveItem( PtrList *this, const size_t requestedIndex )
+{
+ ListPage *page = NULL;
+ size_t pageIndex = 0;
+
+ List_FindItemAddress( this, requestedIndex, &page, &pageIndex );
+
+ if( page != NULL )
+ return ListPage_RemoveItem( page, pageIndex );
+ else
+ List_HandleAddressingError();
+
+ return NULL;
+}
+ /*_____________________________________________________________________
+ **Remove**_____________________________________________________________
+ * Removes the first item in the list with matching pointer.
+ * Note: No check is done for duplicate pointers in the list.
+ *______________________________________________________________________
+ */
+void
+List_Remove( PtrList *this, void * item )
+{
+ size_t index = 0;
+
+ if( List_GetIndexOf( this, item, &index ) )
+ List_RemoveItem( this, index );
+}
+ /*_____________________________________________________________________
+ **GetIndexOf**_________________________________________________________
+ * Inverse of Item(), if pointers in list are unique.
+ * Note: No check is done for duplicate pointers in the list.
+ * Returns TRUE and sets the indexi argument to the first item in the
+ * list with matching pointer, if such an item exists; otherwise
+ * returns FALSE.
+ *______________________________________________________________________
+ */
+PLBOOL
+List_GetIndexOf( const PtrList *this, const void * item, size_t * index )
+{
+ size_t numItemsOnPreviousPages = 0;
+ ListPage *page = NULL;
+
+ for( page = this->firstPage; page != NULL; page = page->next )
+ {
+ const size_t numItemsOnPage = page->numberOfItems;
+ size_t i;
+
+ for( i = 0; i < numItemsOnPage; i++ )
+ if( *( page->items + i ) == item )
+ {
+ *index = numItemsOnPreviousPages + i;
+ return PLTRUE;
+ }
+ numItemsOnPreviousPages += numItemsOnPage;
+ }
+ return PLFALSE;
+}
+#if 0
+static void
+List_BubbleSort( PtrList * list, ListSortComparison comparison )
+{
+ const size_t n = List_NumberOfItems( list );
+ size_t i, j;
+
+ for( i = 0; i < n; i++ )
+ {
+ void *item_i = List_Item( list, i );
+
+ for( j = i + 1; j < n; j++ )
+ {
+ void *item_j = List_Item( list, j );
+
+ if( comparison( item_i, item_j ) > 0 )
+ {
+ List_SwapItems( list, i, j );
+ item_i = item_j;
+ }
+ }
+ }
+}
+#endif
+void
+List_SwapItems( PtrList * v, size_t a, size_t b )
+{
+ ListPage *aPage = NULL, *bPage = NULL;
+ size_t aPageInd, bPageInd;
+
+ List_FindItemAddress( v, a, &aPage, &aPageInd );
+ List_FindItemAddress( v, b, &bPage, &bPageInd );
+
+ if( aPage != NULL && bPage != NULL )
+ {
+ void *temp = *( aPage->items + aPageInd );
+ *( aPage->items + aPageInd ) = *( bPage->items + bPageInd );
+ *( bPage->items + bPageInd ) = temp;
+ }
+}
+ /* Adapted from Kernighan & Ritchie */
+static void
+List_Qsort( PtrList * v, size_t left, size_t right,
+ ListSortComparison comparison )
+{
+ size_t i, last;
+
+ if( left >= right ) /* do nothing if array contains */
+ return; /* fewer than two elements */
+ List_SwapItems( v, left, ( left + right ) / 2); /* move partition */
+ last = left; /* elem to v[0] */
+ for( i = left + 1; i <= right; i++ )
+ {/* SW this could be improved a lot */
+ void * item_i = List_Item( v, i );
+ void * item_left = List_Item( v, left );
+ if( comparison( item_i, item_left ) < 0 )
+ List_SwapItems( v, ++last, i );
+ }
+ List_SwapItems( v, left, last ); /* restore partition elem */
+/* SW NEED TO THINK ABOUT THIS */
+ if( last > 0 ) /* K&R use int, so this isn't an issue for them */
+ List_Qsort( v, left, last - 1, comparison );
+ List_Qsort( v, last + 1, right, comparison );
+}
+
+ /*_____________________________________________________________________
+ **SortAccordingTo**__________________________________________________
+ * Based on the comparison of any two items provided by the comparison
+ * function argument, sorts the list.
+ * Note here it uses a bubble sort, which is slow but easy to
+ * understand. Want something faster? Write your own!
+ *______________________________________________________________________
+ */
+void
+List_SortAccordingTo( PtrList * list, ListSortComparison comparison )
+{
+ size_t n = List_NumberOfItems( list );
+ if( n > 1 )
+ List_Qsort( list, 0, n - 1, comparison );
+}
+
+ /*_____________________________________________________________________
+ **FirstItemSuchThat**__________________________________________________
+ * Takes a ListCondition function, returns the pointer value that
+ * satisfies the condition, otherwise returns NULL,
+ *______________________________________________________________________
+ */
+void *
+List_FirstItemSuchThat( const PtrList *list, ListCondition condition )
+{
+ const size_t n = List_NumberOfItems( list );
+ size_t i;
+
+ for( i = 0; i < n; i++ )
+ if( condition( List_Item( list, i ) ) )
+ return List_Item( list, i );
+
+ return NULL;
+}
+
+ /*_____________________________________________________________________
+ **FindFirstIndexSuchThat**_____________________________________________
+ * Takes a ListCondition function, sets the index pointer to the index
+ * of the first pointer in the list that satisfies condition.
+ * Otherwise returns PLFALSE.
+ *______________________________________________________________________
+ */
+PLBOOL
+List_FindFirstIndexSuchThat( const PtrList *list, ListCondition condition,
+ size_t * index )
+{
+ const size_t n = List_NumberOfItems( list );
+ size_t i;
+
+ for( i = 0; i < n; i++ )
+ if( condition( List_Item( list, i ) ) )
+ {
+ *index = i;
+ return PLTRUE;
+ }
+
+ return PLFALSE;
+}
+
+ /*_____________________________________________________________________
+ **FreeItemsInListAndEmpty**____________________________________________
+ * Lists don't usually delete the things they refer to.
+ * This function takes the list and uses it to free the listed items.
+ *______________________________________________________________________
+ */
+void
+List_FreeItemsInListAndEmpty( PtrList * this )
+{
+ size_t i = List_NumberOfItems( this );
+ void *item = NULL;
+
+ while( i > 0 ) /* Remove items in reverse order for efficeincy */
+ {
+ i--;
+ item = List_Item( this, i );
+ List_RemoveItem( this, i ); /* Remove item before deleting */
+ /* (for consistency) */
+ free( item );
+ }
+}
+ /*_____________________________________________________________________
+ **FindItemAddress**____________________________________________________
+ * Private utility that gets the page and index relative to the page
+ * given the item index. Sets *thePage to NULL if no such index.
+ *______________________________________________________________________
+ */
+void
+List_FindItemAddress( const PtrList *this, size_t itemNo,
+ ListPage ** thePage, size_t *thePageIndex )
+{
+ ListPage *page = NULL;
+ size_t numItemsIncludingThisPage = 0,
+ numItemsOnPreviousPages = 0;
+
+ *thePage = NULL;
+ *thePageIndex = 0;
+
+ for( page = this->firstPage; page != NULL; page = page->next )
+ {
+ numItemsIncludingThisPage += page->numberOfItems;
+
+ if( numItemsIncludingThisPage > itemNo )
+ {
+ *thePage = page;
+ *thePageIndex = itemNo - numItemsOnPreviousPages;
+ return;
+ }
+ numItemsOnPreviousPages = numItemsIncludingThisPage;
+ }
+}
+
+ /*_____________________________________________________________________
+ **Xerox**______________________________________________________________
+ * Private utility that makes a duplicate of the pages in the list.
+ *______________________________________________________________________
+ */
+ListPage *
+List_Xerox( const PtrList *list)
+{
+ ListPage *copy = NULL, *newPage = NULL, *page = list->firstPage;
+
+ if( list->firstPage != NULL )
+ copy = newPage = ListPage_Dup( list->firstPage );
+
+ if( newPage != NULL )
+ do
+ {
+ if( page->next != NULL )
+ {
+ page = page->next;
+ newPage->next = ListPage_Dup( page );
+ }
+ newPage = newPage->next;
+ }
+ while( newPage != NULL );
+ return copy;
+}
+
diff --git a/src/PtrList.h b/src/PtrList.h
new file mode 100644
index 0000000..60f3faf
--- /dev/null
+++ b/src/PtrList.h
@@ -0,0 +1,53 @@
+#ifndef __PTRLIST_HH__
+#define __PTRLIST_HH__
+
+#include <stddef.h>
+
+typedef enum { PLFALSE, PLTRUE } PLBOOL;
+
+typedef struct PtrList_tag PtrList;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+ /* Creation and deletion */
+PtrList * List_New( void );
+PtrList * List_NewWithPageSize( size_t pagesize );
+PtrList * List_MakeCopy( const PtrList * other );
+void List_Delete( PtrList * );
+ /* Counts the items */
+size_t List_NumberOfItems( const PtrList * );
+ /* Item accessors */
+void * List_Item( const PtrList *, size_t index );
+void List_SetItem( PtrList *, size_t index, void * ptr );
+ /* List manipulation */
+void List_Append( PtrList *, void * item );
+void List_Insert( PtrList *, size_t index, void * item );
+void * List_RemoveItem( PtrList *, size_t index );
+void List_SwapItems( PtrList *, size_t a_index, size_t b_index );
+ /* Actions on pointer of particular value */
+void List_Remove( PtrList *, void * item );
+PLBOOL List_GetIndexOf( const PtrList *, const void * item,
+ size_t * index );
+ /* Remove all items from list */
+void List_Empty( PtrList * list );
+ /* Copy another list */
+void List_CopyList( PtrList * list, const PtrList * other );
+ /* Special freeing utility */
+void List_FreeItemsInListAndEmpty( PtrList * );
+ /* Sort and Search */
+typedef int (*ListSortComparison)( const void *, const void * );
+
+void List_SortAccordingTo( PtrList *, ListSortComparison );
+
+typedef PLBOOL (*ListCondition)( const void * );
+
+void * List_FirstItemSuchThat( const PtrList *, ListCondition );
+PLBOOL List_FindFirstIndexSuchThat( const PtrList *,
+ ListCondition condition, size_t * index );
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/PtrList.txt b/src/PtrList.txt
new file mode 100644
index 0000000..a2df8b5
--- /dev/null
+++ b/src/PtrList.txt
@@ -0,0 +1,249 @@
+ PtrList
+ A C module for a list of pointers.
+
+Embodies the idea of a list as a grocery list: the list doesn't contain
+the groceries, it only refers to them; if you throw the list away, you
+don't necessarily lose the produce.
+
+Typical use
+===========
+
+The items in a PtrList are referenced as pointers to void. PtrList can be
+used directly this way, but isn't type-safe. It is usually better to write
+a wrapper around PtrList for each type of data which needs to be listed,
+whose Item() function returns a pointer to an item of that type, etc.
+
+This can be done for simple cases with preprocessor macros, or for more
+involved cases with a separate header and source file.
+
+------------------------------- EXAMPLE ----------------------------------
+
+ ------------------- MyList.h ------------------
+typedef struct PtrList_tag MyListType;
+
+size_t MyListType_NumberOfThings( const MyListType * );
+MyListType * MyListType_New( void );
+...
+
+ ------------------- .c file -------------------
+
+#include "MyList.h"
+
+size_t
+MyListType_NumberOfThings( const MyListType * list ) {
+ return List_NumberOfItems( list );
+}
+
+MyListType *
+MyListType_New() {
+ return (MyListType *)List_New();
+}
+
+-------------------------------------------------------------------
+
+Life-cycle
+==========
+ 1) Create with
+ PtrList_New
+ PtrList_MakeCopy
+
+ 2) Manipulate, pass to functions, etc
+
+ 3) Reclaim memory with
+ PtrList_Delete
+
+Efficiency
+==========
+
+One efficiency concern governed the internal structure of the module, namely
+how to deal with memory needed to deal with the pointers being added.
+
+The simplest thing would be to allocate a block of memory the size of a
+pointer for each item added. For very simple applications making heavy
+use of a list with many items, this is prohibitive.
+
+PtrList does not require a memory allocation per item to append an item.
+Internally, the PtrList maintains a list of pages of pointers, each of which
+contains many pointers. When the first item is appended to an empty PtrList,
+one of these pages is allocated and initialized, and the pointer is written
+in the page. When a second item is appended, it is written directly into
+this existing page. Only when that page is full is another allocated. If an
+item is inserted into a PtrList, it is inserted into the appropriate page,
+and possibly the last item on that page needs to be moved to the next page,
+but if that page is again full, the PtrList just inserts a new empty page and
+puts the remaining item onto the new page.
+
+The only concession made in the API to this paging structure is the creator
+function ListPage_NewWithPageSize( size_t size ), which allows the user to
+set the number of elements on each page. For example, if the maximum number
+of items in the list is known for the application, the page size can be set
+to that maximum, thus avoiding much of the internal paging mechanism.
+
+Limitations
+===========
+
+The PtrList does not (at present) put much effort into compressing pages
+from which items are removed. So if all but one item is removed from each
+page, it will stay that way, rather than compressing the items onto fewer
+pages. One improvment would be to make the list compress itself during a
+Remove call, whenever, say, a page is found to be less than half full.
+
+Various other improvements could be made: the number of items in the list
+could be cached for NumberOfItems.
+
+Name convention
+===============
+
+In some applications, especially when the list items are guaranteed to be
+unique, it makes sense to refer to the pointer items by their values. In
+other applications, it only makes sense to refer to them by their indices.
+
+To distinguish between functions meant for the two cases, those which refer
+to the item by index will have Item in their name, whereas the corresponding
+funcition that refers to the item by value does not: Remove vs RemoveItem.
+
+Namespace
+=========
+
+The header file PtrList_Namespace.h contains macros that locally transforms
+shortened PtrList function names to the full ones. Only names following
+the inclusion of the file are affected.
+
+So long as no other function names in your source file collide with these
+shortened names in your file, you may use them to make your code easier to
+read.
+
+The main creation and deletion functions are not shortened by this file.
+
+Special functions
+=================
+
+Note:
+ Lost_GetIndexOf
+ List_Remove
+These just find the first item pointer whose value is the same as the input
+value. Note that PtrList makes no check as to the uniqueness of pointers
+put into the list.
+
+ List_FreeItemsInListAndEmpty
+
+Is a useful utility, but it isn't really a method of a PtrList in the sense
+that in the common usage of the term 'list', a list doesn't throw away its
+items. Also, be aware that this assumes the items are simple blocks of
+memory allocated with one of the standard C library routines ('malloc', etc).
+It just calls free on each one and removes it in the most efficient way
+(from the end of the list).
+
+Function Reference
+==================
+
+PtrList *
+List_New( void )
+
+ Creates a new empty list.
+
+PtrList *
+List_NewWithPageSize( size_t size )
+
+ Creates a new empty list, and sets the internal page size.
+
+PtrList *
+List_MakeCopy( const PtrList *other )
+
+ Creates a new list containing the same items as does the argument.
+
+void
+List_Delete( PtrList *list )
+
+ Frees the list and memory it allocates internally. DOES NOT
+ do anything to the items pointed to by list items.
+
+static void
+List_HandleAddressingError()
+
+ To be supplied by user of list code. Called when item accesssor
+ is called with an index out of range.
+
+void
+List_Empty( PtrList * this )
+
+ Removes all the items on the list (does nothing to items pointed
+ to by the list items).
+
+size_t
+List_NumberOfItems( const PtrList *this )
+
+ Returns the number of items in the list.
+
+void
+List_Append( PtrList *this, void * newItem )
+
+ Puts a new item on the end of the list.
+
+void
+List_InsertItem( PtrList *this, size_t index, void * newItem )
+
+ Inserts the item at the specified index, shifting indices of existing
+ list items as necessary. If index is greater than or equal to the
+ number of items initially in the list, the item is just appended.
+
+void *
+List_Item( const PtrList *this, size_t requestedIndex )
+
+ Returns the item of given index; returns NULL if no such index.
+ The items are indexed beginning with 0;
+
+void
+List_SetItem( PtrList *this, size_t requestedIndex, void *value )
+
+ Sets the item of given index. Calls user-supplied addressing
+ handler if no such item exists.
+
+void
+List_CopyList( PtrList *list, const PtrList * other )
+
+ Empties this list and puts items from other list in it.
+
+void *
+List_RemoveItem( PtrList *list, size_t index )
+
+ Removes the item of given index from the list.
+ Returns a pointer to the item removed, or NULL if item not found.
+
+void
+List_Remove( PtrList *list, void * item )
+
+ Removes the first item in the list with pointer identical to 'item'.
+
+PLBOOL
+List_GetIndexOf( const PtrList *this, const void * item, size_t * index )
+
+ Returns TRUE and sets the index argument to the first item in the
+ list with pointer identical to 'item', if such an item exists;
+ otherwise returns FALSE.
+ Note: is inverse of Item(), if pointers in list are unique.
+
+void
+List_SortAccordingTo( PtrList * list, ListSortComparison comparison )
+
+ Based on the comparison of any two items provided by the comparison
+ function argument, sorts the list.
+
+void *
+List_FirstItemSuchThat( const PtrList *list, ListCondition condition )
+
+ Takes a ListCondition function, returns the pointer value that
+ satisfies the condition, otherwise returns NULL,
+
+PLBOOL
+List_FindFirstIndexSuchThat( const PtrList *list, ListCondition condition,
+ size_t * index )
+ Takes a ListCondition function, sets the index pointer to the index
+ of the first pointer in the list that satisfies condition.
+ Otherwise returns FALSE.
+
+void
+List_FreeItemsInListAndEmpty( PtrList * this )
+
+ Lists don't usually delete the things they refer to.
+ This function takes the list and uses it to free the listed items.
diff --git a/src/PtrList_Namespace.h b/src/PtrList_Namespace.h
new file mode 100644
index 0000000..6c9c811
--- /dev/null
+++ b/src/PtrList_Namespace.h
@@ -0,0 +1,37 @@
+#ifndef __PTRLIST_NAMESPACE_HH__
+#define __PTRLIST_NAMESPACE_HH__
+
+#include "PtrList.h"
+
+/* A poor man's namespace for the PtrList module */
+
+#define NumberOfItems( a ) \
+ List_NumberOfItems( a )
+#define Remove( a, b ) \
+ List_Remove( a, b )
+#define Item( a, b ) \
+ List_Item( a, b )
+#define Insert( a, b, c ) \
+ List_Insert( a, b, c )
+#define SetItem( a, b, c ) \
+ List_SetItem( a, b, c )
+#define Append( a, b ) \
+ List_Append( a, b )
+#define RemoveItem( a, b ) \
+ List_RemoveItem( a, b )
+#define SwapItems( a, b, c ) \
+ List_SwapItems( a, b, c )
+#define Remove( a, b ) \
+ List_Remove( a, b )
+#define GetIndexOf( a, b, c ) \
+ List_GetIndexOf( a, b, c )
+#define DeleteItemsAndEmpty( a ) \
+ List_DeleteItemsAndEmpty( a )
+#define SortAccordingTo( a, b ) \
+ List_SortAccordingTo( a, b )
+#define FirstItemSuchThat( a, b ) \
+ List_FirstItemSuchThat( a, b )
+#define FindFirstIndexSuchThat( a, b ) \
+ List_FindFirstIndexSuchThat( a, b )
+
+#endif
diff --git a/src/make.code.defn b/src/make.code.defn
index 83438d1..67328bf 100644
--- a/src/make.code.defn
+++ b/src/make.code.defn
@@ -2,7 +2,7 @@
# $Header$
# Source files in this directory
-SRCS = Groups.c Startup.c IO.c Processors.c HostNames.c
+SRCS = Groups.c Startup.c IO.c Processors.c HostNames.c PtrList.c HTTPD_FileList.c
# Subdirectories containing source files
SUBDIRS =