From b55bae51688e9d97c6848b0a5e073dcc8851723f Mon Sep 17 00:00:00 2001 From: swhite Date: Mon, 19 Apr 2004 13:10:13 +0000 Subject: 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 --- param.ccl | 8 + src/Groups.c | 11 +- src/HTTPD_FileList.c | 64 +++++ src/HTTPD_FileList.h | 62 +++++ src/HostNames.c | 4 - src/IO.c | 480 ++++++++++++++++++++--------------- src/PtrList.c | 656 ++++++++++++++++++++++++++++++++++++++++++++++++ src/PtrList.h | 53 ++++ src/PtrList.txt | 249 ++++++++++++++++++ src/PtrList_Namespace.h | 37 +++ src/make.code.defn | 2 +- 11 files changed, 1407 insertions(+), 219 deletions(-) create mode 100644 src/HTTPD_FileList.c create mode 100644 src/HTTPD_FileList.h create mode 100644 src/PtrList.c create mode 100644 src/PtrList.h create mode 100644 src/PtrList.txt create mode 100644 src/PtrList_Namespace.h 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 #include #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) "Message:" "\n" "\n" - "\n" + "

\n\n

\n" "\n" "" ); - ConcatCString(message, "\n" ); - - HTTP_SendString(request, message); - } + Truncate( message, 0 ); + SortFilesAccordingTo( filelist, Variable_Thorn_Slice ); - HTTP_Send(request,"
\n" "

Messages:

" 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 -#include -#include - #ifdef HAVE_UNISTD_H #include #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 -#include -#include -#include -#include +#include "cctk_Parameters.h" #include #ifdef HAVE_UNISTD_H #include #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, "", depth ); + ConcatCString( message, "\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, "", depth ); + ConcatCString( message, "" + "\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, "", depth ); + ConcatCString( message, "" + "\n" + "\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, "\n" ); - HTTP_Send(request, "Cactus Downloadable Files\n"); + HTTP_SendString( request, message); + + HTTP_Send( request, "\n" ); + HTTP_Send( request, "Cactus Downloadable Files\n"); HTTP_SetHeadInfo( message); - HTTP_SendString(request, message ); + HTTP_Send( request, "\n"); + HTTP_SendString( request, message ); - HTTP_Send(request, "\n\n"); + HTTP_Send( request, "\n\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, "

Downloadable Files

"); + HTTP_Send( request, "

Downloadable Files

\n"); - HTTP_Send(request, + HTTP_Send( request, "

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.

\n " - "

Some of these output files can be directly viewed on \n" - "a browser on the simulation \n" - "viewport

\n" - "

Many IO methods have steerable parameters which \n" - "allow you to e.g. add fields and customise behaviour.\n" - "Depending on your authorisation, you can access the \n" - "parameter steering page

\n" + " local machine, you can change the browser properties to launch\n" + " files directly to visualization clients.

\n " + "

Some of these output files can be directly viewed on \n" + "a browser on the simulation \n" + "viewport

\n" + "

Many IO methods have steerable parameters which \n" + "allow you to e.g. add fields and customise behaviour.\n" + "Depending on your authorisation, you can access the \n" + "parameter steering page" + "

\n"); + HTTP_Send( request, "
\n" - "
" ); + Concat( message, file->varname ); + ConcatCString( message, " " ); + IndentAndConcatCString( message, "
 " ); + Concat( message, file->thorn ); + IndentAndConcatCString( message, "
  " ); + Concat( message, file->slice ); + + ConcatCString( message, "\n" ); + IndentAndConcatCString( message, "\n", depth ); + IndentAndConcatCString( message, "linkname ); + ConcatCString( message, "\">" ); + Concat( message, file->filename ); + ConcatCString( message, "\n" ); + IndentAndConcatCString( message, "\n", depth ); + IndentAndConcatCString( message, "", depth ); + Concat( message, file->description ); + ConcatCString( message, "\n" ); + IndentAndConcatCString( message, "
\n" - "\n" - "\n" - "\n\n"); + "
File NameVariableDescription
\n" + "\n" + "\n" + "\n
\n" + "VariableThorn Slice File Description
\n" + "\n" + ); - for (list = filelist; list; list = list->next) - { - SetToCString(message, "
linkname ); - ConcatCString(message, "\">" ); - ConcatCString(message, list->filename ); - ConcatCString(message, "" ); - ConcatCString(message, list->data.varname ); - ConcatCString(message, "" ); - ConcatCString(message, list->data.description ); - ConcatCString(message, "
\n"); + HTTP_Send( request, "\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
"); + HTTP_Send( request, "\n"); + + 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, "\n\n"); - HTTP_Send(request, "Error 500: Internal Error\n"); - HTTP_Send(request, "\n\n"); - HTTP_Send(request, "

Unable to open " ); - HTTP_Send(request, list->filename ); - HTTP_Send(request, "

\n"); - HTTP_Send(request, "\n\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, "\n\n"); + HTTP_Send( request, "Error 500: Internal Error\n"); + HTTP_Send( request, "\n\n"); + HTTP_Send( request, "

Unable to open " ); + HTTP_SendString( request, file->filename ); + HTTP_Send( request, "

\n"); + HTTP_Send( request, "\n\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, "\n\n" ); - HTTP_Send(request, "Error 404: Not Found\n" ); - HTTP_Send(request, "\n\n" ); - HTTP_Send(request, "

" ); - HTTP_Send(request, HTTP_URI( request ) ); - HTTP_Send(request, " does not exist

\n" ); - HTTP_Send(request, "\n\n" ); + HTTP_Send( request, "\n\n" ); + HTTP_Send( request, "Error 404: Not Found\n" ); + HTTP_Send( request, "\n\n" ); + HTTP_Send( request, "

" ); + HTTP_Send( request, HTTP_URI( request ) ); + HTTP_Send( request, " does not exist

\n" ); + HTTP_Send( request, "\n\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, "\n\n"); - HTTP_Send(request, "Cactus Downloadable Files\n"); + HTTP_Send( request, "\n\n"); + HTTP_Send( request, "Cactus Downloadable Files\n"); HTTP_SetHeadInfo( message); - HTTP_SendString(request, message ); - - HTTP_Send(request, "\n\n"); - /* HTTP_Write out the header part. */ - - HTTP_SetContentHeaderString(GH, 0, message, NULL); - HTTP_SendString(request, message); - - HTTP_Send(request, "

Viewport

\n"); - - HTTP_Send(request, + HTTP_Send( request, "\n"); + + HTTP_SendString( request, message ); + + HTTP_Send( request, "\n\n"); + + HTTP_SetContentHeaderString( GH, 0, message, NULL); + HTTP_SendString( request, message); + + HTTP_Send( request, "

Viewport

\n"); + + HTTP_Send( request, "

This page displays certain types of the output files \n" "from the download page \n" "as images (currently only JPEGs [mime type image/jpeg]).

\n" @@ -397,57 +457,61 @@ static int ViewportFilePage(const cGH *GH, httpRequest *request, void *data) "parameter steering page

\n" "
\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, - "\n" - "\n" - "\n"); + HTTP_Send( request, + "
Variable
File Name
DescriptionImage
\n" + "\n" + "\n\n"); foundone = 1; } - HTTP_Send(request, "\n" ); - HTTP_Send(request, "\n" ); - HTTP_Send(request, "\n" ); - HTTP_Send(request, "\n" ); - HTTP_Send(request, "\n" ); + HTTP_Send( request, "\n" ); + HTTP_Send( request, "\n" ); + HTTP_Send( request, "\n" ); + HTTP_Send( request, "\n" ); + HTTP_Send( request, "\n" ); } } - if (!foundone) + if( foundone) + HTTP_Send( request, "
Variable
Slice
DescriptionImage
" ); - HTTP_Send(request, list->data.varname ); - HTTP_Send(request, "
\n" ); - HTTP_Send(request, "linkname ); - HTTP_Send(request, "\">" ); - HTTP_Send(request, list->filename ); - HTTP_Send(request, "\n" ); - HTTP_Send(request, "
" ); - HTTP_Send(request, list->data.description ); - HTTP_Send(request, "linkname ); - HTTP_Send(request, "\">" ); - HTTP_Send(request, "linkname ); - HTTP_Send(request, "\" />" ); - HTTP_Send(request, "
" ); + HTTP_SendString( request, file->varname ); + HTTP_Send( request, "
\n" ); + HTTP_Send( request, "" ); + HTTP_SendString( request, file->slice ); + HTTP_Send( request, "" ); + HTTP_Send( request, "
" ); + HTTP_SendString( request, file->description ); + HTTP_Send( request, "linkname ); + HTTP_Send( request, "\">" ); + HTTP_Send( request, "linkname ); + HTTP_Send( request, "\" alt=\"" ); + HTTP_SendString( request, file->linkname ); + HTTP_Send( request, "\"/>" ); + HTTP_Send( request, "
\n"); + else { - HTTP_Send(request, "\n

No viewable images registered!

\n" + HTTP_Send( request, "\n

No viewable images registered!

\n" "
\n"); } + HTTP_Send( request, "
\n"); - HTTP_Send(request, "\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 +#include + +#ifdef macintosh +#include +#endif + +#define ITEMSONFULLPAGE 62 +#define TAKEDEFAULTSIZE 0 +#define MIN(a,b) (aitems = 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 + +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 = -- cgit v1.2.3