The following patch implements the get_mgmt_items hook in the scoreboard
(PRELIM)
I have included the patch inline -- as well as a attachment.
I have also include a module (destined for the experimental directory)
which will show the
results (in HTML & XML format)
to use add the following in httpd.conf:
<Location /mgmt-status>
    SetHandler mgmt-status
</Location

then http://server/mgmt-status/?scoreboard.current.summary
to show the summary table
or
http://server/mgmt-status/?scorebaord.current.summary.status.waiting

to show the number of threads waiting
or
http://server/mgmt-status/?scoreboard.current.worker.*.thread.*.status

to show each individual thread's status

It still needs a bit of work, but it is ready for you guys to rip it
apart.

--Ian

Index: scoreboard.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
retrieving revision 1.24
diff -u -r1.24 scoreboard.c
--- scoreboard.c        2001/05/22 01:31:12     1.24
+++ scoreboard.c        2001/06/18 22:40:57
@@ -88,6 +88,416 @@
 #include "apr_shmem.h"
 static apr_shmem_t *scoreboard_shm = NULL;
 #endif
+
+/*
+ * Sets a individual detail level for a given child/thread pair 
+ * 
+ */
+struct server_status_desc {
+       char id;
+       const char*key;
+       const char *description;
+};
+
+static const struct server_status_desc server_status_desc[] = {
+       {SERVER_DEAD,           "dead",         "Server Dead"},
+       {SERVER_STARTING,       "starting",     "Server Starting Up"},
+       {SERVER_READY,          "waiting",      "Waiting for
connection"},
+       {SERVER_BUSY_READ,      "reading",      "Reading a client
request"},
+       {SERVER_BUSY_WRITE,     "writing",      "Processing a client
request"},
+       {SERVER_BUSY_KEEPALIVE,"keepalive",     "Waiting for more
requests via keepalive"},
+       {SERVER_BUSY_LOG,       "log",          "Logging the Request"},
+       {SERVER_BUSY_DNS,       "dns",          "Looking up a
hostname"},
+       {SERVER_GRACEFUL,       "gracefull","server is gracefully
finishing request"},
+       {SERVER_ACCEPTING,      "accepting","thread is accepting
connections"},
+       {SERVER_QUEUEING,       "queueing",     "thread is putting
connection on the queue"},
+       {SERVER_IDLE_KILL,      "idlekill",     "Server is cleaning up
idle children"},
+       {-1, "unknown","unknown/invalid key"}
+};
+
+/*
+ * TODO: move helper functions out of scoreboard 
+ * mgmt_set_mgmt_long -- sets a line which represents a 'long'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_long(apr_pool_t *p, const
char*name, const char*desc,long val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_long;
+       h->v.i_value = val;
+       return h;
+}
+/*
+ * mgmt_set_mgmt_string -- sets a line which represents a 'string'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_string(apr_pool_t *p, const
char*name, const char*desc,const char*val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_string;
+       h->v.s_value = val;
+       return h;
+}
+/*
+ * mgmt_set_mgmt_hash -- sets a line which represents a group of other
keys 
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_hash(apr_pool_t *p, const
char*name, const char*desc,apr_hash_t *val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_hash;
+       h->v.h_value = val;
+       return h;
+}
+
+/*
+ * get variables related to a individual thread 
+ */
+static int mgmt_get_var_current_worker_thread_detail(apr_pool_t *p,
const char*keyPrefix,
+       const char**elements, int level, const int maxLevel, apr_hash_t
*ht,
+       int child_num, int thread_num )
+{
+       int bWantAll=0;
+       worker_score ws_record;
+       ap_mgmt_item_t *h;
+
+       const char*word;
+       if (level >= maxLevel)
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 )
+                       word = NULL;
+               else
+                       word=elements[level];
+       }
+
+
+       if ( child_num > HARD_SERVER_LIMIT || thread_num >
HARD_THREAD_LIMIT) {
+                       return DECLINED;
+       }
+
+       ws_record = ap_scoreboard_image->servers[child_num][thread_num];
+
+       if ( word == NULL || strcmp(word,"thread_num")==0) {
+               h = mgmt_set_mgmt_long(p, "thread_num", "Thread
Number",ws_record.thread_num);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"thread_num",NULL),APR_HASH_KEY_STRING,h);
+       }
+       /* XXX: ?? should be handled by MPM perhaps? or in a
arch-specific call?*/
+#if APR_HAS_THREADS
+       if ( word == NULL || strcmp(word,"tid")==0) {
+               h = mgmt_set_mgmt_long(p, "tid", "Thread ID (OS
Specific)",(long)ws_record.tid);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"tid",NULL),APR_HASH_KEY_STRING,h);
+       }
+#endif
+       if ( word == NULL || strcmp(word,"status")==0) {
+               int i=0;
+               while ( server_status_desc[i].id != -1 &&
+                               server_status_desc[i].id !=
ws_record.status) {
+                       i++;
+               }
+
+               if (i == -1 ) {
+                       h = mgmt_set_mgmt_string(p,
"status","??unknown/invalid status??","??unknown??");
+               } else {
+                       h = mgmt_set_mgmt_string(p,
"status",server_status_desc[i].description,server_status_desc[i].key);
+               }
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_slot")==0) {
+               h = mgmt_set_mgmt_long(p, "access_slot","Access Counts
for this slot",ws_record.access_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_slot",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_connection")==0) {
+               h = mgmt_set_mgmt_long(p, "access_connection","Access
Counts for this connection",ws_record.conn_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_connection",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_child")==0) {
+               h = mgmt_set_mgmt_long(p, "access_child","Access Counts
for this child",ws_record.my_access_count);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_child",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       if ( word == NULL || strcmp(word,"bytes_slot")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_slot","bytes served for
this slot",ws_record.bytes_served);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_slot",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"bytes_connection")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_connection","bytes
served for this connection",ws_record.conn_bytes);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_connection",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"bytes_child")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_child","bytes served
for this child",ws_record.my_bytes_served);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_child",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       if ( word == NULL || strcmp(word,"request")==0) {
+               h = mgmt_set_mgmt_string(p, "request","the request
currently being processed",apr_pstrdup(p,ws_record.request));
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"request",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       return OK;
+}
+static int mgmt_get_var_current_worker_child(apr_pool_t *p, const
char*keyPrefix, const char**elements, int level, const int maxLevel,
apr_hash_t *ht, int child )
+{
+       int i;
+    process_score ps_record;
+       const char*word;
+       ap_mgmt_item_t *h;
+
+       if ( child > HARD_SERVER_LIMIT )
+               return DECLINED;
+       ps_record = ap_scoreboard_image->parent[child];
+
+
+
+       if (level >= maxLevel)
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 )
+                       word = NULL;
+               else
+                       word=elements[level];
+       }
+
+       if ( word == NULL || strcmp(word,"pid")==0) {
+               h = mgmt_set_mgmt_long(p,"pid","Process
ID",ps_record.pid);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"pid",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"generation")==0) {
+               h = mgmt_set_mgmt_long(p,"generation","Process
Generation",ps_record.generation);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"generation",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"type")==0) {
+               h = mgmt_set_mgmt_string(p,"scoreboardType","Scoreboard
Type",
+                               (ps_record.sb_type == SB_SHARED)?
"shared":"not shared");
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"type",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL  || strcmp(word,"status")==0) {
+               h = mgmt_set_mgmt_string(p,"status","Process Status",
+                       (ps_record.process_status == SB_WORKING) ?
"working" : "idle_die");
+
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"worker_count")==0) {
+               h =
mgmt_set_mgmt_long(p,"worker_count","#Threads",ps_record.worker_threads);
+
apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"worker_count",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"thread")==0) {
+               if (ps_record.process_status == SB_WORKING) {
+                       if ( level +1 >= maxLevel ||
strcmp(elements[level+1],"*")==0 ) {
+                               for (i=0;i<ps_record.worker_threads;i++)
{
+                                       apr_hash_t *t =apr_hash_make(p);
+                                       h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",i),"thread",t);
+
apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",i),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_thread_detail(p, "",
elements,level+2,maxLevel,t,child,i);
+                               }
+                       } else {
+                               int thread = atoi(elements[level+1]);
+                               if ( level +2 >= maxLevel ||
strcmp(elements[level+2],"*")==0 ) {
+                                       apr_hash_t *t =apr_hash_make(p);
+                                       h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",thread),"thread",t);
+
apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",thread),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_thread_detail(p, "",
elements,level+2,maxLevel,t,child,thread);
+                               } else
+
mgmt_get_var_current_worker_thread_detail(p,
apr_psprintf(p,"%s%s.%d.",keyPrefix,"thread",thread),
elements,level+2,maxLevel, ht,child,thread);
+                       }
+               }
+       }
+       return DECLINED;
+
+}
+static int mgmt_get_var_current(apr_pool_t *p, const char*keyPrefix,
const char**elements, int level, const int maxLevel, apr_hash_t *ht )
+{
+    worker_score ws_record;
+       int i,j;
+       const unsigned int KBYTE=1024;
+       unsigned long lres=0;
+       unsigned long bytes=0;
+       unsigned long count=0;
+       unsigned long bcount=0;
+       unsigned long kbcount=0;
+       unsigned long status_count[SERVER_NUM_STATUS];
+       int bWantDetail=0;
+       int bWantSummary=0;
+       apr_hash_t *hDetail=NULL;
+       ap_mgmt_item_t *h;
+       char*keyBase;
+       const char*word;
+       if (level >= maxLevel)
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 )
+                       word = NULL;
+               else;
+                       word=elements[level];
+       }
+
+       if (word == NULL || strcmp(word,"worker")==0) {
+               bWantDetail=1;
+               if ((level+1) < maxLevel &&
strcmp(elements[level+1],"*") != 0 ) {
+                       int child_num;
+
+                       child_num=atoi(elements[level+1]);
+
keyBase=apr_pstrcat(p,keyPrefix,".worker.",elements[level+1],".",NULL);
+                       return
mgmt_get_var_current_worker_child(p,keyBase,elements,level+2,maxLevel,ht,child_num);
+                       }
+
+       }
+       if (word == NULL || strcmp(word,"summary")==0) {
+               bWantSummary=1;
+       }
+
+       if (bWantSummary==0 && bWantDetail == 0 )
+               return DECLINED;
+
+       for (i=0;i<SERVER_NUM_STATUS;i++) {
+               status_count[i]=0;
+       }
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
+               if ( bWantDetail ==1  ) {
+                       apr_hash_t *t =apr_hash_make(p);
+                       h =
mgmt_set_mgmt_hash(p,apr_psprintf(p,"%d",i),"child",t);
+                       apr_hash_set(ht,
apr_psprintf(p,"%s.worker.%d",keyPrefix,i),APR_HASH_KEY_STRING,h);
+
mgmt_get_var_current_worker_child(p,"",elements,level+2,maxLevel,t,i);
+               }
+
+               if ( bWantSummary == 1 ) {
+                       for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
+                               ws_record =
ap_scoreboard_image->servers[i][j];
+                               status_count[ws_record.status]++;
+                               lres = ws_record.access_count;
+                               bytes = ws_record.bytes_served;
+                               count += lres;
+                               bcount += bytes;
+                               if (bcount >= KBYTE) {
+                                       kbcount += (bcount >> 10);
+                                       bcount = bcount & 0x3ff;
+                               }
+                       }
+               }
+       }
+
+       if (bWantSummary==1) {
+               apr_hash_t *hSub;
+               char*baseKey;
+               const char *sumWord;
+
+               if (level+1 >= maxLevel ||
strcmp(elements[level+1],"*")==0)  {
+                       hSub = apr_hash_make(p);
+                       h =
mgmt_set_mgmt_hash(p,"summary","summary",hSub);
+                       apr_hash_set(ht,
apr_pstrcat(p,keyPrefix,".summary",NULL),APR_HASH_KEY_STRING,h);
+                       baseKey="";
+                       sumWord=NULL;
+               }
+               else {
+                       sumWord=elements[level+1];
+                       hSub = ht;
+                       baseKey =
apr_pstrcat(p,keyPrefix,".summary.",NULL);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"kbytes")==0) {
+                       h = mgmt_set_mgmt_long(p,"kbytes","KB
Served",kbcount);
+                       if (baseKey)
+                               apr_hash_set(hSub,
apr_pstrcat(p,baseKey,"kbytes",NULL),APR_HASH_KEY_STRING,h);
+                       else
+                               apr_hash_set(hSub,
"kbytes",APR_HASH_KEY_STRING,h);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"request")==0) {
+                       h = mgmt_set_mgmt_long(p,"request","Requests
served",count);
+                       if (baseKey)
+                               apr_hash_set(hSub,
apr_pstrcat(p,baseKey,"request",NULL),APR_HASH_KEY_STRING,h);
+                       else
+                               apr_hash_set(hSub,
"requests",APR_HASH_KEY_STRING,h);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"status")==0) {
+                       const char*statusKey;
+                       apr_hash_t *hStatus;
+                       int i,j;
+                       if ( level+2>= maxLevel ||elements[ level+2] ==
"*" ) {
+                               hStatus = apr_hash_make(p);
+                               h =
mgmt_set_mgmt_hash(p,"status","status summary",hStatus);
+//
apr_hash_set(hSub,server_status_desc[j].key ,APR_HASH_KEY_STRING,h);
+
+
apr_hash_set(hSub,apr_pstrcat(p,baseKey,"status",NULL),APR_HASH_KEY_STRING,h);
+
+                               for (i=0;i<SERVER_NUM_STATUS;i++) {
+                                       j=0;
+                                       while ( server_status_desc[j].id
!= -1 &&
+
server_status_desc[j].id != i) {
+                                               j++;
+                                       }
+                                       h =
mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[i]);
+
apr_hash_set(hStatus,server_status_desc[j].key ,APR_HASH_KEY_STRING,h);
+                               }
+                       }
+                       else {
+                               int j;
+                               char *statusBase;
+                               statusKey=elements[level+2];
+                               statusBase =
apr_pstrcat(p,baseKey,"status.",NULL);
+                               j=0;
+                               while ( server_status_desc[j].id != -1
&&
+
strcmp(server_status_desc[j].key,statusKey)!=0) {
+                                       j++;
+                               }
+                               h =
mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[server_status_desc[j].id
 ]);
+
apr_hash_set(hSub,apr_pstrcat(p,statusBase,server_status_desc[j].key,NULL) 
,APR_HASH_KEY_STRING,h);
+
+                       }
+               }
+       }
+
+       return DECLINED;
+}
+static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t
*ht)
+{
+       apr_array_header_t *elements;
+       const char*word=NULL;
+       char*line=NULL;
+       const char **a;
+       char*last=NULL;
+       int i;
+
+       int bMatchAll=0;
+
+       if (val == NULL )
+               return DECLINED;
+       line = apr_pstrdup(p,val);
+       elements = apr_array_make( p,5,sizeof(char**));
+       word = apr_strtok(line,".",&last);
+       while (word != NULL ) {
+               *(const char**)apr_array_push(elements) = word;
+               word = apr_strtok(NULL,".",&last);
+       }
+
+       a= (const char**)elements->elts ;
+       i=0;
+       if (strcmp(a[i],"scoreboard")!=0 && strcmp(a[i],"*")!=0) {
+               return DECLINED;
+
+       }
+       i++;
+       word= a[i];
+
+       if ( word && strcmp(word,"*")==0 )
+               word = NULL;
+
+
+       if (word == NULL || strcmp(word,"current")==0) {
+               mgmt_get_var_current(p,"scoreboard.current",a,
i+1,elements->nelts,ht);
+       }
+       /*
+        * Info would go here
+        */
+       return DECLINED;
+}
 /*
  * ToDo:
  * This function should be renamed to cleanup_shared
@@ -189,6 +599,7 @@
     ap_scoreboard_image->global.running_generation = running_gen;
     ap_restart_time = apr_time_now();
     apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard,
apr_pool_cleanup_null);
+       ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL,
APR_HOOK_MIDDLE);
 }
 
 /* Routines called to deal with the scoreboard image




-- 
Ian Holsman 
Performance Measurement and Analysis
CNET Networks
PH: (415) 364 8608
Index: scoreboard.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
retrieving revision 1.24
diff -u -r1.24 scoreboard.c
--- scoreboard.c        2001/05/22 01:31:12     1.24
+++ scoreboard.c        2001/06/18 22:40:57
@@ -88,6 +88,416 @@
 #include "apr_shmem.h"
 static apr_shmem_t *scoreboard_shm = NULL;
 #endif
+
+/*
+ * Sets a individual detail level for a given child/thread pair 
+ * 
+ */
+struct server_status_desc {
+       char id;
+       const char*key;
+       const char *description;
+};
+
+static const struct server_status_desc server_status_desc[] = {
+       {SERVER_DEAD,           "dead",         "Server Dead"},
+       {SERVER_STARTING,       "starting",     "Server Starting Up"},
+       {SERVER_READY,          "waiting",      "Waiting for connection"},
+       {SERVER_BUSY_READ,      "reading",      "Reading a client request"},
+       {SERVER_BUSY_WRITE,     "writing",      "Processing a client request"},
+       {SERVER_BUSY_KEEPALIVE,"keepalive",     "Waiting for more requests via 
+keepalive"},
+       {SERVER_BUSY_LOG,       "log",          "Logging the Request"},
+       {SERVER_BUSY_DNS,       "dns",          "Looking up a hostname"},
+       {SERVER_GRACEFUL,       "gracefull","server is gracefully finishing request"},
+       {SERVER_ACCEPTING,      "accepting","thread is accepting connections"},
+       {SERVER_QUEUEING,       "queueing",     "thread is putting connection on the 
+queue"},
+       {SERVER_IDLE_KILL,      "idlekill",     "Server is cleaning up idle children"},
+       {-1, "unknown","unknown/invalid key"}
+};
+
+/*
+ * TODO: move helper functions out of scoreboard 
+ * mgmt_set_mgmt_long -- sets a line which represents a 'long'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_long(apr_pool_t *p, const char*name, const 
+char*desc,long val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_long;
+       h->v.i_value = val;
+       return h;
+}
+/*
+ * mgmt_set_mgmt_string -- sets a line which represents a 'string'
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_string(apr_pool_t *p, const char*name, const 
+char*desc,const char*val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_string;
+       h->v.s_value = val;
+       return h;
+}
+/*
+ * mgmt_set_mgmt_hash -- sets a line which represents a group of other keys 
+ */
+static ap_mgmt_item_t* mgmt_set_mgmt_hash(apr_pool_t *p, const char*name, const 
+char*desc,apr_hash_t *val)
+{
+       ap_mgmt_item_t* h;
+       h = apr_palloc(p,sizeof(ap_mgmt_item_t));
+       h->name= name;
+       h->description = desc;
+       h->vtype= ap_mgmt_type_hash;
+       h->v.h_value = val;
+       return h;
+}
+
+/*
+ * get variables related to a individual thread 
+ */
+static int mgmt_get_var_current_worker_thread_detail(apr_pool_t *p, const 
+char*keyPrefix, 
+       const char**elements, int level, const int maxLevel, apr_hash_t *ht, 
+       int child_num, int thread_num )
+{
+       int bWantAll=0;
+       worker_score ws_record;
+       ap_mgmt_item_t *h;
+
+       const char*word;
+       if (level >= maxLevel)          
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 ) 
+                       word = NULL;
+               else
+                       word=elements[level];
+       }
+
+
+       if ( child_num > HARD_SERVER_LIMIT || thread_num > HARD_THREAD_LIMIT) {
+                       return DECLINED;
+       }
+       
+       ws_record = ap_scoreboard_image->servers[child_num][thread_num];
+
+       if ( word == NULL || strcmp(word,"thread_num")==0) {
+               h = mgmt_set_mgmt_long(p, "thread_num", "Thread 
+Number",ws_record.thread_num);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"thread_num",NULL),APR_HASH_KEY_STRING,h);
+       }
+       /* XXX: ?? should be handled by MPM perhaps? or in a arch-specific call?*/
+#if APR_HAS_THREADS
+       if ( word == NULL || strcmp(word,"tid")==0) {
+               h = mgmt_set_mgmt_long(p, "tid", "Thread ID (OS 
+Specific)",(long)ws_record.tid);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"tid",NULL),APR_HASH_KEY_STRING,h);
+       }
+#endif
+       if ( word == NULL || strcmp(word,"status")==0) {
+               int i=0;
+               while ( server_status_desc[i].id != -1 && 
+                               server_status_desc[i].id != ws_record.status) {        
+ 
+                       i++;
+               }
+
+               if (i == -1 ) {
+                       h = mgmt_set_mgmt_string(p, "status","??unknown/invalid 
+status??","??unknown??");
+               } else {
+                       h = mgmt_set_mgmt_string(p, 
+"status",server_status_desc[i].description,server_status_desc[i].key);
+               }               
+
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_slot")==0) {
+               h = mgmt_set_mgmt_long(p, "access_slot","Access Counts for this 
+slot",ws_record.access_count);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_slot",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_connection")==0) {
+               h = mgmt_set_mgmt_long(p, "access_connection","Access Counts for this 
+connection",ws_record.conn_count);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_connection",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"access_child")==0) {
+               h = mgmt_set_mgmt_long(p, "access_child","Access Counts for this 
+child",ws_record.my_access_count);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"access_child",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       if ( word == NULL || strcmp(word,"bytes_slot")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_slot","bytes served for this 
+slot",ws_record.bytes_served);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_slot",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"bytes_connection")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_connection","bytes served for this 
+connection",ws_record.conn_bytes);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_connection",NULL),APR_HASH_KEY_STRING,h);
+       }
+       if ( word == NULL || strcmp(word,"bytes_child")==0) {
+               h = mgmt_set_mgmt_long(p, "bytes_child","bytes served for this 
+child",ws_record.my_bytes_served);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"bytes_child",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       if ( word == NULL || strcmp(word,"request")==0) {
+               h = mgmt_set_mgmt_string(p, "request","the request currently being 
+processed",apr_pstrdup(p,ws_record.request));
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"request",NULL),APR_HASH_KEY_STRING,h);
+       }
+
+       return OK;
+}
+static int mgmt_get_var_current_worker_child(apr_pool_t *p, const char*keyPrefix, 
+const char**elements, int level, const int maxLevel, apr_hash_t *ht, int child )
+{
+       int i;
+    process_score ps_record;
+       const char*word;
+       ap_mgmt_item_t *h;
+
+       if ( child > HARD_SERVER_LIMIT )
+               return DECLINED;
+       ps_record = ap_scoreboard_image->parent[child];
+
+
+
+       if (level >= maxLevel)          
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 ) 
+                       word = NULL;
+               else
+                       word=elements[level];
+       }
+
+       if ( word == NULL || strcmp(word,"pid")==0) {
+               h = mgmt_set_mgmt_long(p,"pid","Process ID",ps_record.pid);     
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"pid",NULL),APR_HASH_KEY_STRING,h);     
+       }
+       if ( word == NULL || strcmp(word,"generation")==0) {
+               h = mgmt_set_mgmt_long(p,"generation","Process 
+Generation",ps_record.generation);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"generation",NULL),APR_HASH_KEY_STRING,h);    
+  
+       }
+       if ( word == NULL || strcmp(word,"type")==0) {
+               h = mgmt_set_mgmt_string(p,"scoreboardType","Scoreboard Type",
+                               (ps_record.sb_type == SB_SHARED)? "shared":"not 
+shared");
+
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"type",NULL),APR_HASH_KEY_STRING,h);    
+       }
+       if ( word == NULL  || strcmp(word,"status")==0) {
+               h = mgmt_set_mgmt_string(p,"status","Process Status",
+                       (ps_record.process_status == SB_WORKING) ? "working" : 
+"idle_die");
+
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"status",NULL),APR_HASH_KEY_STRING,h);  
+       }
+       if ( word == NULL || strcmp(word,"worker_count")==0) {
+               h = 
+mgmt_set_mgmt_long(p,"worker_count","#Threads",ps_record.worker_threads);
+               
+apr_hash_set(ht,apr_pstrcat(p,keyPrefix,"worker_count",NULL),APR_HASH_KEY_STRING,h);  
+  
+       }
+       if ( word == NULL || strcmp(word,"thread")==0) {
+               if (ps_record.process_status == SB_WORKING) {
+                       if ( level +1 >= maxLevel || strcmp(elements[level+1],"*")==0 
+) {
+                               for (i=0;i<ps_record.worker_threads;i++) {
+                                       apr_hash_t *t =apr_hash_make(p);
+                                       h = 
+mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",i),"thread",t);
+                                       
+apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",i),APR_HASH_KEY_STRING,h);
+  
+                                       mgmt_get_var_current_worker_thread_detail(p, 
+"", elements,level+2,maxLevel,t,child,i);
+                               }
+                       } else {
+                               int thread = atoi(elements[level+1]);
+                               if ( level +2 >= maxLevel || 
+strcmp(elements[level+2],"*")==0 ) {
+                                       apr_hash_t *t =apr_hash_make(p);
+                                       h = 
+mgmt_set_mgmt_hash(p,apr_psprintf(p,"thread.%d",thread),"thread",t);
+                                       
+apr_hash_set(ht,apr_psprintf(p,"%s%s%d",keyPrefix,"thread.",thread),APR_HASH_KEY_STRING,h);
+     
+                                       mgmt_get_var_current_worker_thread_detail(p, 
+"", elements,level+2,maxLevel,t,child,thread);
+                               } else                          
+                                       mgmt_get_var_current_worker_thread_detail(p, 
+apr_psprintf(p,"%s%s.%d.",keyPrefix,"thread",thread), elements,level+2,maxLevel, 
+ht,child,thread);
+                       }
+               } 
+       }
+       return DECLINED;
+
+}
+static int mgmt_get_var_current(apr_pool_t *p, const char*keyPrefix, const 
+char**elements, int level, const int maxLevel, apr_hash_t *ht )
+{
+    worker_score ws_record;
+       int i,j;
+       const unsigned int KBYTE=1024;
+       unsigned long lres=0;
+       unsigned long bytes=0;
+       unsigned long count=0;
+       unsigned long bcount=0;
+       unsigned long kbcount=0;
+       unsigned long status_count[SERVER_NUM_STATUS];
+       int bWantDetail=0;
+       int bWantSummary=0;
+       apr_hash_t *hDetail=NULL;       
+       ap_mgmt_item_t *h;
+       char*keyBase;
+       const char*word;
+       if (level >= maxLevel)          
+               word=NULL;
+       else {
+               if ( strcmp(elements[level],"*")==0 ) 
+                       word = NULL;
+               else;
+                       word=elements[level];
+       }
+
+       if (word == NULL || strcmp(word,"worker")==0) {
+               bWantDetail=1;
+               if ((level+1) < maxLevel && strcmp(elements[level+1],"*") != 0 ) {
+                       int child_num;
+       
+                       child_num=atoi(elements[level+1]);                             
+ 
+                       
+keyBase=apr_pstrcat(p,keyPrefix,".worker.",elements[level+1],".",NULL);
+                       return 
+mgmt_get_var_current_worker_child(p,keyBase,elements,level+2,maxLevel,ht,child_num);
+                       }
+
+       }
+       if (word == NULL || strcmp(word,"summary")==0) {
+               bWantSummary=1;
+       }
+
+       if (bWantSummary==0 && bWantDetail == 0 )
+               return DECLINED;
+
+       for (i=0;i<SERVER_NUM_STATUS;i++) {
+               status_count[i]=0;
+       }
+
+    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
+               if ( bWantDetail ==1  ) {
+                       apr_hash_t *t =apr_hash_make(p);
+                       h = mgmt_set_mgmt_hash(p,apr_psprintf(p,"%d",i),"child",t);    
+ 
+                       apr_hash_set(ht, 
+apr_psprintf(p,"%s.worker.%d",keyPrefix,i),APR_HASH_KEY_STRING,h);
+                       
+mgmt_get_var_current_worker_child(p,"",elements,level+2,maxLevel,t,i);
+               }
+               
+               if ( bWantSummary == 1 ) {
+                       for (j = 0; j < HARD_THREAD_LIMIT; ++j) {        
+                               ws_record = ap_scoreboard_image->servers[i][j];
+                               status_count[ws_record.status]++;
+                               lres = ws_record.access_count;
+                               bytes = ws_record.bytes_served;
+                               count += lres;
+                               bcount += bytes;
+                               if (bcount >= KBYTE) {
+                                       kbcount += (bcount >> 10);
+                                       bcount = bcount & 0x3ff;
+                               }
+                       }                       
+               }
+       }
+
+       if (bWantSummary==1) {
+               apr_hash_t *hSub;
+               char*baseKey;
+               const char *sumWord;
+
+               if (level+1 >= maxLevel || strcmp(elements[level+1],"*")==0)  {
+                       hSub = apr_hash_make(p);
+                       h = mgmt_set_mgmt_hash(p,"summary","summary",hSub);
+                       apr_hash_set(ht, 
+apr_pstrcat(p,keyPrefix,".summary",NULL),APR_HASH_KEY_STRING,h);
+                       baseKey="";
+                       sumWord=NULL;
+               }
+               else {
+                       sumWord=elements[level+1];
+                       hSub = ht;
+                       baseKey = apr_pstrcat(p,keyPrefix,".summary.",NULL);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"kbytes")==0) {
+                       h = mgmt_set_mgmt_long(p,"kbytes","KB Served",kbcount);
+                       if (baseKey)
+                               apr_hash_set(hSub, 
+apr_pstrcat(p,baseKey,"kbytes",NULL),APR_HASH_KEY_STRING,h);
+                       else
+                               apr_hash_set(hSub, "kbytes",APR_HASH_KEY_STRING,h);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"request")==0) {
+                       h = mgmt_set_mgmt_long(p,"request","Requests served",count);
+                       if (baseKey)
+                               apr_hash_set(hSub, 
+apr_pstrcat(p,baseKey,"request",NULL),APR_HASH_KEY_STRING,h);
+                       else
+                               apr_hash_set(hSub, "requests",APR_HASH_KEY_STRING,h);
+               }
+               if (sumWord == NULL || strcmp(sumWord,"status")==0) {
+                       const char*statusKey;
+                       apr_hash_t *hStatus;
+                       int i,j;
+                       if ( level+2>= maxLevel ||elements[ level+2] == "*" ) {
+                               hStatus = apr_hash_make(p);
+                               h = mgmt_set_mgmt_hash(p,"status","status 
+summary",hStatus);
+//                             apr_hash_set(hSub,server_status_desc[j].key 
+,APR_HASH_KEY_STRING,h);
+
+                               
+apr_hash_set(hSub,apr_pstrcat(p,baseKey,"status",NULL),APR_HASH_KEY_STRING,h);
+
+                               for (i=0;i<SERVER_NUM_STATUS;i++) {
+                                       j=0;
+                                       while ( server_status_desc[j].id != -1 && 
+                                                       server_status_desc[j].id != i) 
+{                
+                                               j++;
+                                       }
+                                       h = 
+mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[i]);
+                                       apr_hash_set(hStatus,server_status_desc[j].key 
+,APR_HASH_KEY_STRING,h);                                 
+                               }
+                       }
+                       else {
+                               int j;
+                               char *statusBase;
+                               statusKey=elements[level+2];
+                               statusBase = apr_pstrcat(p,baseKey,"status.",NULL);
+                               j=0;
+                               while ( server_status_desc[j].id != -1 && 
+                                               
+strcmp(server_status_desc[j].key,statusKey)!=0) {               
+                                       j++;
+                               }
+                               h = 
+mgmt_set_mgmt_long(p,server_status_desc[j].key,server_status_desc[j].description,status_count[server_status_desc[j].id
+ ]);
+                               
+apr_hash_set(hSub,apr_pstrcat(p,statusBase,server_status_desc[j].key,NULL) 
+,APR_HASH_KEY_STRING,h);
+                       
+                       }
+               }
+       }
+
+       return DECLINED;
+}
+static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t *ht) 
+{
+       apr_array_header_t *elements;
+       const char*word=NULL;
+       char*line=NULL;
+       const char **a;
+       char*last=NULL;
+       int i;
+
+       int bMatchAll=0;
+       
+       if (val == NULL )
+               return DECLINED;
+       line = apr_pstrdup(p,val);
+       elements = apr_array_make( p,5,sizeof(char**));
+       word = apr_strtok(line,".",&last);
+       while (word != NULL ) {
+               *(const char**)apr_array_push(elements) = word;
+               word = apr_strtok(NULL,".",&last);
+       }       
+
+       a= (const char**)elements->elts ;
+       i=0;
+       if (strcmp(a[i],"scoreboard")!=0 && strcmp(a[i],"*")!=0) {
+               return DECLINED;
+               
+       }
+       i++;
+       word= a[i];
+
+       if ( word && strcmp(word,"*")==0 ) 
+               word = NULL;
+
+
+       if (word == NULL || strcmp(word,"current")==0) {
+               mgmt_get_var_current(p,"scoreboard.current",a, i+1,elements->nelts,ht);
+       }
+       /*
+        * Info would go here
+        */
+       return DECLINED;
+}
 /*
  * ToDo:
  * This function should be renamed to cleanup_shared
@@ -189,6 +599,7 @@
     ap_scoreboard_image->global.running_generation = running_gen;
     ap_restart_time = apr_time_now();
     apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard, apr_pool_cleanup_null);
+       ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL, APR_HOOK_MIDDLE);
 }
 
 /* Routines called to deal with the scoreboard image
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "util_script.h"
#include <time.h>
#include "http_log.h"

#define CORE_PRIVATE

#include "apr.h"
#include "apr_strings.h"
#include "apr_hooks.h"
#include "apr_hash.h"

#define APR_WANT_STRFUNC
#include "apr_want.h"


/* mod_mgmt.c - by Ian Holsman <[EMAIL PROTECTED]>
 *
 * Basic Management module
 */

AP_MODULE_DECLARE_DATA module mgmt_module;

typedef struct {
    int level;	
} mgmt_config;



/* simple little function to write an APR error string and exit */

static void apr_err(const char *s, apr_status_t rv)
{
    char buf[120];

    fprintf(stderr,
	    "%s: %s (%d)\n",
	    s, apr_strerror(rv, buf, sizeof buf), rv);
    exit(rv);
}

/*
 * Create a configuration specific to this module for a server or directory
 * location, and fill it with the default settings.
 *
 * The API says that in the absence of a merge function, the record for the
 * closest ancestor is used exclusively.  That's what we want, so we don't
 * bother to have such a function.
 */

static void *mkconfig(apr_pool_t *p)
{
    mgmt_config *cfg = apr_pcalloc(p, sizeof(mgmt_config));

    cfg->level = 0;
    return cfg;
}

/*
 * Respond to a callback to create configuration record for a server or
 * vhost environment.
 */
static void *create_mconfig_for_server(apr_pool_t *p, server_rec *s)
{
    return mkconfig(p);
}

/*
 * Respond to a callback to create a config record for a specific directory.
 */
static void *create_mconfig_for_directory(apr_pool_t *p, char *dir)
{
    return mkconfig(p);
}
static void	mgmt_dump_hash_xml(request_rec *r, apr_hash_t *ht, int level) 
{
	apr_hash_index_t *iterator;
	iterator = apr_hash_first(ht);
	while (iterator) {
		ap_mgmt_item_t *line;
		char*key;
		apr_hash_this(iterator,&key,NULL,&line);
		ap_rprintf(r,"<%s><name>%s</name><desc>%s</desc>\n", key, line->name, line->description );
		if ( line->vtype== ap_mgmt_type_long ) {			
			ap_rprintf(r," <long>%ld</long>\n", line->v.i_value);
		} else if (line->vtype == ap_mgmt_type_string) {
			ap_rputs(" <string>", r);
			ap_rputs(line->v.s_value , r);
			ap_rputs("</string>\n", r);
		} else if ( line->vtype == ap_mgmt_type_hash) {
			mgmt_dump_hash_xml(r, line->v.h_value, level+1);
		} else {
			ap_rprintf(r,"<unknown>%ld</unknown>\n",line->vtype );
		}
		ap_rprintf(r,"</%s>\n",key);
		iterator = apr_hash_next(iterator);
	}
}
static void	mgmt_dump_hash_html(request_rec *r, apr_hash_t *ht, int level) 
{
	apr_hash_index_t *iterator;
	iterator = apr_hash_first(ht);
	while (iterator) {
		ap_mgmt_item_t *line;
		char*key;
		apr_hash_this(iterator,&key,NULL,&line);
		ap_rprintf(r,"Level: %d Key: <i>%s</i> Name: %s Desc: %s ", level, key, line->name , line->description );
		if ( line->vtype== ap_mgmt_type_long ) {			
			ap_rprintf(r," <strong>%ld</strong>", line->v.i_value);
		} else if (line->vtype == ap_mgmt_type_string) {
			ap_rputs(" <strong>", r);
			ap_rputs(line->v.s_value , r);
			ap_rputs("</strong>", r);
		} else if ( line->vtype == ap_mgmt_type_hash) {
			ap_rputs("<ul>", r);
			mgmt_dump_hash_html(r, line->v.h_value, level+1);
			ap_rputs("</ul>", r);
		} else {
			ap_rprintf(r,"??unknown value type %ld??",line->vtype );
		}
		ap_rputs("<br>\n",r);
		iterator = apr_hash_next(iterator);
	}
}
static int mgmt_handler(request_rec *r)
{
	apr_hash_t *ht;
	int bXML=0;

    if (strcmp(r->handler, "mgmt-status")!=0) {
        return DECLINED;
    }
    r->allowed = (1 << M_GET);
    if (r->method_number != M_GET)
		return DECLINED;


	if (ap_strstr(r->uri,"/xml") != NULL ) {
		bXML=1;
	}
	if (bXML==1) {
		r->content_type = "text/xml";
		ap_rputs("<?xml version=\"1.0\" ?>\n", r);
		ap_rputs("<status>\n", r);
		ap_rvputs(r, "<servername>",ap_get_server_name(r), "</servername>\n", NULL);


	} else {
		r->content_type = "text/html";
		ap_rputs(DOCTYPE_HTML_3_2
			 "<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n", r);
		ap_rputs("<H1>Apache Server Status for ", r);
		ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL);
	}
	ht = apr_hash_make(r->pool);	

	
	if (r->args) {
		char*args;
		char*token;
		char*strtok_state;

		args=apr_pstrdup(r->pool,r->args);
		while ((token=apr_strtok(args,"&",&strtok_state))!= NULL) {
			args=NULL;	
			ap_run_get_mgmt_items(r->pool,token, ht );
		}
	}
	else
		ap_run_get_mgmt_items(r->pool,"*", ht );

	if (bXML==1) {
		mgmt_dump_hash_xml(r, ht,0);
		ap_rputs("</status>\n", r);
	} else {
		mgmt_dump_hash_html(r, ht,0);
		ap_rputs("</BODY></HTML>", r);
	}


	return OK;
}
static const char *set_mgmt(cmd_parms *cmd, void *mconfig, const char *name)
{
    mgmt_config *dcfg = (mgmt_config *) mconfig;
	dcfg->level = atoi(name);
	return NULL;
}
/*
 * Define the directives specific to this module.  This structure is referenced
 * later by the 'module' structure.
 */
static const command_rec mgmt_cmds[] =
{
    AP_INIT_TAKE1("mgmt", set_mgmt, NULL, RSRC_CONF, "Default Level for Walks"),

    { NULL }
};

static int mgmt_get_vars( apr_pool_t *p, const char*val, apr_hash_t *ht) {
	ap_mgmt_item_t *h;
	char *key;

	int bMatchAll =0;
	int bMatchModule=0;
	int bMatched=0;
	
	if ( strcmp(val,"*") ==0 || strcmp(val,"test.*")==0) {
		bMatchModule=1;
		if ( val[0]=='*') 
			bMatchAll=1;
	}
	if (bMatchModule == 1 || strcmp(val, "test.123")==0){
		bMatched=1;
		key = "test.123";
		h = apr_palloc(p, sizeof (ap_mgmt_item_t));
		h->description =  "Dummy line 1";
		h->name = "mod_mgmt test123";
		h->vtype= ap_mgmt_type_string;
		h->v.s_value = "This is a dummy string value";
		apr_hash_set(ht, key,strlen(key),(void*)h);
	}
	if (bMatchModule == 1 || strcmp(val, "test.234")==0) {
		bMatched=1;
		key = "test.234";
		h = apr_palloc(p, sizeof (ap_mgmt_item_t));
		h->description = "Dummy line 2";
		h->name= "mod_mgmt";
		h->vtype = ap_mgmt_type_long;

		h->v.i_value = 34L;
		apr_hash_set(ht, key,strlen(key),(void*)h);
	}

	if (bMatchModule == 1 || strncmp("test.456",val,strlen( "test.456"))==0) {
		apr_hash_t *subHash;
		ap_mgmt_item_t *subLine;
		int bSubMatchAll=0;
		bMatched=1;

		if (strcmp("test.456.*",val)==0) {
			bSubMatchAll=1;
		}

		if (strcmp("test.456",val)==0 || bMatchModule ==1 || bSubMatchAll==1) {
			key = "test.456";
			h = apr_palloc(p, sizeof (ap_mgmt_item_t));
			h->description = "Dummy line 3 (summary)";
			h->name ="mod_mgmt";
			if (bSubMatchAll == 0 || bMatchModule ==1) {
				h->vtype = ap_mgmt_type_string;
				h->v.s_value=apr_pstrdup(p,"Summary of line 3");
			} else {
				h->vtype = ap_mgmt_type_hash;
				subHash = apr_hash_make(p);
				subLine =apr_palloc(p,sizeof( ap_mgmt_item_t));
				subLine->description =apr_pstrdup(p,"sub line 1" );
				subLine->name=NULL;
				subLine->vtype = ap_mgmt_type_string;
				subLine->v.s_value =apr_pstrdup(p,"subLine Value 1");
				apr_hash_set(subHash, "subkey1",strlen("subkey1"),(void*)subLine);

				subLine =apr_palloc(p,sizeof( ap_mgmt_item_t));
				subLine->description =apr_pstrdup(p,"sub line 2" );
				subLine->name=NULL;
				subLine->vtype = ap_mgmt_type_string;
				subLine->v.s_value=apr_pstrdup(p,"subLine Value 2");
				apr_hash_set(subHash, "subkey2",strlen("subkey2"),(void*)subLine);
				
				h->v.h_value = subHash;
			} 
		}
		else if (strcmp("test.456.subkey1",val)==0) { 
			key = apr_pstrdup(p,val);
			h = apr_palloc(p, sizeof (ap_mgmt_item_t));
			h->description = apr_pstrdup(p, "Dummy line 3 subkey1");
			h->name = "mod_mgmt";
			h->vtype = ap_mgmt_type_string;
			h->v.s_value =apr_pstrdup(p,"subLine Value 1");			
		} else if (strcmp("test.456.subkey2",val)==0){
			key = apr_pstrdup(p,val);
			h = apr_palloc(p, sizeof (ap_mgmt_item_t));
			h->description = "Dummy line 3 subkey2";
			h->name= "mod_mgmt";
			h->vtype = ap_mgmt_type_string;
			h->v.s_value = "subLine Value 2";
		} else {
			bMatched=0;
			return DECLINED;
		}
		apr_hash_set(ht, key,strlen(key),(void*)h);
	}

	if (bMatchAll ==1 ) 
		return DECLINED;

	if ( bMatched == 1)
		return OK;

	return DECLINED;
}
static void register_hooks(apr_pool_t *p)
{
	ap_hook_handler(mgmt_handler, NULL, NULL, APR_HOOK_MIDDLE);
	ap_hook_get_mgmt_items(mgmt_get_vars, NULL,NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA mgmt_module =
{
    STANDARD20_MODULE_STUFF,
    create_mconfig_for_directory,  /* create per-dir config */
    NULL,                       /* merge per-dir config */
    create_mconfig_for_server,  /* server config */
    NULL,                       /* merge server config */
    mgmt_cmds,               /* command apr_table_t */
    register_hooks		/* register hooks */
};

Reply via email to