aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 =