2003-07-10 Casper S. Hornstrup <chorns@users.sourceforge.net>
authorCasper Hornstrup <chorns@users.sourceforge.net>
Thu, 10 Jul 2003 12:29:02 +0000 (12:29 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Thu, 10 Jul 2003 12:29:02 +0000 (12:29 +0000)
* rules.mak (XSLTPROC): Add.
* tools/Makefile: Add rgenstat.
* apistatus.lst: New file.
* tools/rgenstat: New directory.
* tools/rgenstat/.cvsignore: New file.
* tools/rgenstat/llmosrt.c: Ditto.
* tools/rgenstat/Makefile: Ditto.
* tools/rgenstat/rgenstat.c: Ditto.
* tools/rgenstat/web: New directory.
* tools/rgenstat/web/*.gif: New files.
* tools/rgenstat/web/.cvsignore: New file.
* tools/rgenstat/web/rapistatus.css: Ditto.
* tools/rgenstat/web/rapistatus.js: Ditto.
* tools/rgenstat/web/rapistatus.xsl: Ditto.

svn path=/trunk/; revision=5035

20 files changed:
reactos/ChangeLog
reactos/apistatus.lst [new file with mode: 0755]
reactos/rules.mak
reactos/tools/Makefile
reactos/tools/rgenstat/.cvsignore [new file with mode: 0755]
reactos/tools/rgenstat/Makefile [new file with mode: 0755]
reactos/tools/rgenstat/llmosrt.c [new file with mode: 0755]
reactos/tools/rgenstat/rgenstat.c [new file with mode: 0755]
reactos/tools/rgenstat/web/.cvsignore [new file with mode: 0755]
reactos/tools/rgenstat/web/c.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/f.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/i.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/rapistatus.css [new file with mode: 0755]
reactos/tools/rgenstat/web/rapistatus.js [new file with mode: 0755]
reactos/tools/rgenstat/web/rapistatus.xsl [new file with mode: 0755]
reactos/tools/rgenstat/web/sc.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/tb.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/tm.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/tp.gif [new file with mode: 0755]
reactos/tools/rgenstat/web/u.gif [new file with mode: 0755]

index 110dbc5..da5a36e 100644 (file)
@@ -1,3 +1,20 @@
+2003-07-10  Casper S. Hornstrup  <chorns@users.sourceforge.net>
+
+       * rules.mak (XSLTPROC): Add.
+       * tools/Makefile: Add rgenstat.
+       * apistatus.lst: New file.
+       * tools/rgenstat: New directory.
+       * tools/rgenstat/.cvsignore: New file.
+       * tools/rgenstat/llmosrt.c: Ditto.
+       * tools/rgenstat/Makefile: Ditto.
+       * tools/rgenstat/rgenstat.c: Ditto.
+       * tools/rgenstat/web: New directory.
+       * tools/rgenstat/web/*.gif: New files.
+       * tools/rgenstat/web/.cvsignore: New file.
+       * tools/rgenstat/web/rapistatus.css: Ditto.
+       * tools/rgenstat/web/rapistatus.js: Ditto.
+       * tools/rgenstat/web/rapistatus.xsl: Ditto.
+
 2003-07-10  Casper S. Hornstrup  <chorns@users.sourceforge.net>
 
        * drivers/fs/vfat/misc.c (VfatLockControl): Move it so it is placed
 2003-07-10  Casper S. Hornstrup  <chorns@users.sourceforge.net>
 
        * drivers/fs/vfat/misc.c (VfatLockControl): Move it so it is placed
diff --git a/reactos/apistatus.lst b/reactos/apistatus.lst
new file mode 100755 (executable)
index 0000000..fa11fae
--- /dev/null
@@ -0,0 +1,30 @@
+; Format:\r
+;   COMPONENT_NAME PATH_TO_COMPONENT_SOURCES\r
+; COMPONENT_NAME            - Name of the component. Eg. kernel32.dll.\r
+; PATH_TO_COMPONENT_SOURCES - Relative path to sources (relative to\r
+;                             where rgenstat is run from).\r
+advapi32.dll reactos/lib/advapi32\r
+crtdll.dll reactos/lib/crtdll\r
+gdi32.dll reactos/lib/gdi32\r
+iphlpapi.dll reactos/lib/iphlpapi\r
+kernel32.dll reactos/lib/kernel32\r
+msvcrt.dll reactos/lib/msvcrt\r
+ole32.dll reactos/lib/ole32\r
+oleaut32.dll reactos/lib/oleaut32\r
+rpcrt4.dll reactos/lib/rpcrt4\r
+secur32.dll reactos/lib/secur32\r
+shell32.dll reactos/lib/shell32\r
+snmpapi.dll reactos/lib/snmpapi\r
+user32.dll reactos/lib/user32\r
+version.dll reactos/lib/version\r
+winmm.dll reactos/lib/winmm\r
+winspool.dll reactos/lib/winspool\r
+ws2_32.dll reactos/lib/ws2_32\r
+wsock32.dll reactos/lib/wsock32\r
+videoprt.dll reactos/drivers/dd/videoprt\r
+ndis.dll reactos/drivers/net/ndis\r
+tdi.dll reactos/drivers/net/tdi\r
+class2.sys reactos/drivers/storage/class2\r
+scsiport.sys reactos/drivers/storage/scsiport\r
+ntoskrnl.exe reactos/ntoskrnl\r
+win32k.sys reactos/subsys/win32k\r
index d91f330..8db52b3 100644 (file)
@@ -95,6 +95,7 @@ RMKDIR = $(TOOLS_PATH)/rmkdir
 RSYM = $(TOOLS_PATH)/rsym
 RTOUCH = $(TOOLS_PATH)/rtouch
 MC = $(TOOLS_PATH)/wmc/wmc
 RSYM = $(TOOLS_PATH)/rsym
 RTOUCH = $(TOOLS_PATH)/rtouch
 MC = $(TOOLS_PATH)/wmc/wmc
+XSLTPROC = xsltproc
 
 
 # Maybe we can delete these soon
 
 
 # Maybe we can delete these soon
index c38b40a..39f73f4 100644 (file)
@@ -14,7 +14,7 @@ TOOLS = \
 
 CLEAN_FILES = $(TOOLS)
 
 
 CLEAN_FILES = $(TOOLS)
 
-all: $(TOOLS) wmc_target cdmake_target mkhive_target
+all: $(TOOLS) wmc_target cdmake_target mkhive_target rgenstat_target
 
 buildno$(EXE_POSTFIX): buildno.c ../include/reactos/version.h
        $(HOST_CC) $(CFLAGS) -o buildno$(EXE_POSTFIX) buildno.c
 
 buildno$(EXE_POSTFIX): buildno.c ../include/reactos/version.h
        $(HOST_CC) $(CFLAGS) -o buildno$(EXE_POSTFIX) buildno.c
@@ -99,12 +99,18 @@ cdmake_target:
 mkhive_target:
        $(MAKE) -C mkhive mkhive$(EXE_POSTFIX)
 
 mkhive_target:
        $(MAKE) -C mkhive mkhive$(EXE_POSTFIX)
 
+rgenstat_target:
+       $(MAKE) -C rgenstat rgenstat$(EXE_POSTFIX)
+
+.PHONY: wmc_target cdmake_target mkhive_target rgenstat_target
+
 
 ifeq ($(HOST),mingw32-linux)
 clean:
        $(MAKE) -C cdmake clean
        $(MAKE) -C mkhive clean
        $(MAKE) -C wmc clean
 
 ifeq ($(HOST),mingw32-linux)
 clean:
        $(MAKE) -C cdmake clean
        $(MAKE) -C mkhive clean
        $(MAKE) -C wmc clean
+       $(MAKE) -C rgenstat clean
        rm mkconfig
        rm $(TOOLS)
 endif
        rm mkconfig
        rm $(TOOLS)
 endif
@@ -113,6 +119,7 @@ clean:
        $(MAKE) -C cdmake clean
        $(MAKE) -C mkhive clean
        $(MAKE) -C wmc clean
        $(MAKE) -C cdmake clean
        $(MAKE) -C mkhive clean
        $(MAKE) -C wmc clean
+       $(MAKE) -C rgenstat clean
        del *$(EXE_POSTFIX)
 endif
 
        del *$(EXE_POSTFIX)
 endif
 
diff --git a/reactos/tools/rgenstat/.cvsignore b/reactos/tools/rgenstat/.cvsignore
new file mode 100755 (executable)
index 0000000..75f1ce1
--- /dev/null
@@ -0,0 +1,10 @@
+rgenstat
+*.coff
+*.d
+*.exe
+*.o
+*.sym
+*.dsp
+*.dsw
+*.ncb
+*.opt
diff --git a/reactos/tools/rgenstat/Makefile b/reactos/tools/rgenstat/Makefile
new file mode 100755 (executable)
index 0000000..4d5291c
--- /dev/null
@@ -0,0 +1,43 @@
+PATH_TO_TOP = ../..
+
+TARGET=rgenstat$(EXE_POSTFIX)
+
+all: $(TARGET)
+
+OBJECTS = rgenstat.o llmosrt.o
+
+CLEAN_FILES = *.o rgenstat$(EXE_POSTFIX)
+
+HOST_CFLAGS = -I.
+
+rgenstat.o: rgenstat.c
+       $(HOST_CC) $(HOST_CFLAGS) -c rgenstat.c -o rgenstat.o
+
+llmosrt.o: llmosrt.c
+       $(HOST_CC) $(HOST_CFLAGS) -c llmosrt.c -o llmosrt.o
+
+rgenstat$(EXE_POSTFIX): $(OBJECTS)
+       $(HOST_CC) $(OBJECTS) -o rgenstat$(EXE_POSTFIX)
+
+ifeq ($(HOST),mingw32-linux)
+clean:
+       rm -f *.o
+       rm -f rgenstat$(EXE_POSTFIX)
+endif
+ifeq ($(HOST),mingw32-windows)
+clean:
+       del *.o
+       del rgenstat$(EXE_POSTFIX)
+endif
+
+web/apistatus.html: web/apistatus.xml web/rapistatus.xsl
+       $(XSLTPROC) -o web/apistatus.html web/rapistatus.xsl web/apistatus.xml
+
+web: web/apistatus.html
+       -
+
+.phony: clean web
+
+include $(PATH_TO_TOP)/rules.mak
+
+# EOF
diff --git a/reactos/tools/rgenstat/llmosrt.c b/reactos/tools/rgenstat/llmosrt.c
new file mode 100755 (executable)
index 0000000..b901175
--- /dev/null
@@ -0,0 +1,106 @@
+/* $Id: llmosrt.c,v 1.1 2003/07/10 12:29:02 chorns Exp $ */
+/* A Linked-List Memory Sort
+   by Philip J. Erdelsky
+   pje@acm.org
+   http://www.alumni.caltech.edu/~pje/
+*/
+
+/* According to his website, this file was released into the public domain by Phillip J. Erdelsky */
+
+
+#include <stdio.h>
+
+void *sort_linked_list(void *p, unsigned index, int (*compare)(void *, void *))
+{
+  unsigned base;
+  unsigned long block_size;
+
+  struct record
+  {
+    struct record *next[1];
+    /* other members not directly accessed by this function */
+  };
+
+  struct tape
+  {
+    struct record *first, *last;
+    unsigned long count;
+  } tape[4];
+
+  /* Distribute the records alternately to tape[0] and tape[1]. */
+
+  tape[0].count = tape[1].count = 0L;
+  tape[0].first = NULL;
+  base = 0;
+  while (p != NULL)
+  {
+    struct record *next = ((struct record *)p)->next[index];
+    ((struct record *)p)->next[index] = tape[base].first;
+    tape[base].first = ((struct record *)p);
+    tape[base].count++;
+    p = next;
+    base ^= 1;
+  }
+
+  /* If the list is empty or contains only a single record, then */
+  /* tape[1].count == 0L and this part is vacuous.               */
+
+  for (base = 0, block_size = 1L; tape[base+1].count != 0L;
+    base ^= 2, block_size <<= 1)
+  {
+    int dest;
+    struct tape *tape0, *tape1;
+    tape0 = tape + base;
+    tape1 = tape + base + 1;
+    dest = base ^ 2;
+    tape[dest].count = tape[dest+1].count = 0;
+    for (; tape0->count != 0; dest ^= 1)
+    {
+      unsigned long n0, n1;
+      struct tape *output_tape = tape + dest;
+      n0 = n1 = block_size;
+      while (1)
+      {
+        struct record *chosen_record;
+        struct tape *chosen_tape;
+        if (n0 == 0 || tape0->count == 0)
+        {
+          if (n1 == 0 || tape1->count == 0)
+            break;
+          chosen_tape = tape1;
+          n1--;
+        }
+        else if (n1 == 0 || tape1->count == 0)
+        {
+          chosen_tape = tape0;
+          n0--;
+        }
+        else if ((*compare)(tape0->first, tape1->first) > 0)
+        {
+          chosen_tape = tape1;
+          n1--;
+        }
+        else
+        {
+          chosen_tape = tape0;
+          n0--;
+        }
+        chosen_tape->count--;
+        chosen_record = chosen_tape->first;
+        chosen_tape->first = chosen_record->next[index];
+        if (output_tape->count == 0)
+          output_tape->first = chosen_record;
+        else
+          output_tape->last->next[index] = chosen_record;
+        output_tape->last = chosen_record;
+        output_tape->count++;
+      }
+    }
+  }
+
+  if (tape[base].count > 1L)
+    tape[base].last->next[index] = NULL;
+  return tape[base].first;
+}
+
+/* EOF */
diff --git a/reactos/tools/rgenstat/rgenstat.c b/reactos/tools/rgenstat/rgenstat.c
new file mode 100755 (executable)
index 0000000..5e278cb
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ * Generate a file with API status information from a list
+ * of files in a directory.
+ * Casper S. Hornstrup <chorns@users.sourceforge.net>
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <io.h>
+#include <dos.h>
+#else
+#include <sys/io.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+#include <ctype.h>
+#ifndef WIN32
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+#define DIR_SEPARATOR_CHAR '/'
+#define DIR_SEPARATOR_STRING "/"
+#else
+#define DIR_SEPARATOR_CHAR '\\'
+#define DIR_SEPARATOR_STRING "\\"
+#endif
+
+#define TAG_UNKNOWN -1
+#define TAG_IMPLEMENTED 0
+#define TAG_UNIMPLEMENTED 1
+
+typedef struct _API_INFO
+{
+  struct _API_INFO *next;
+  int tag_id;
+  char name[100];
+} API_INFO, *PAPI_INFO;
+
+
+PAPI_INFO sort_linked_list(PAPI_INFO,
+    unsigned, int (*)(PAPI_INFO, PAPI_INFO));
+
+
+static FILE *in;
+static FILE *out;
+static char *file;
+static FILE *file_handle = NULL;
+static char *file_buffer = NULL;
+static unsigned int file_size = 0;
+static int file_pointer = 0;
+static char tagname[200];
+static PAPI_INFO api_info_list = NULL;
+
+
+static char*
+convert_path(char* origpath)
+{
+   char* newpath;
+   int i;
+   
+   newpath = strdup(origpath);
+   
+   i = 0;
+   while (newpath[i] != 0)
+     {
+#ifndef WIN32
+       if (newpath[i] == '\\')
+         {
+            newpath[i] = '/';
+         }
+#else
+#ifdef WIN32
+       if (newpath[i] == '/')
+         {
+            newpath[i] = '\\';
+         }
+#endif 
+#endif 
+       i++;
+     }
+   return(newpath);
+}
+
+static void
+write_line(char *line)
+{
+  int n_out;
+  char buf[200];
+
+  memset(buf, 0, sizeof(buf));
+  strcpy(buf, line);
+  /* Terminate the line */
+  buf[strlen(buf)] = '\r';
+  buf[strlen(buf)] = '\n';
+
+  n_out = fwrite(&buf[0], 1, strlen(buf), out);
+}
+
+
+static void
+read_file(char *filename)
+{
+  file_handle = fopen(filename, "rb");
+  if (file_handle == NULL)
+    {
+      printf("Can't open %s\n", filename);
+      exit(1);
+    }
+
+  // Get the size of the file
+  fseek(file_handle, 0, SEEK_END);
+  file_size = ftell(file_handle);
+
+  // Load it all into memory
+  file_buffer = malloc(file_size);
+  if (file_buffer == NULL)
+    {
+      fclose(file_handle);
+      printf("Out of memory\n");
+      exit(1);
+    }
+  fseek(file_handle, 0, SEEK_SET);
+  if (file_size > 0)
+    {
+      if (fread (file_buffer, 1, file_size, file_handle) < 1)
+        {
+          fclose(file_handle);
+          printf("Read error in file %s\n", filename);
+          exit(1);
+        }
+    }
+
+  file_pointer = 0;
+}
+
+static void
+close_file()
+{
+  free(file_buffer);
+  file_buffer = NULL;
+  fclose(file_handle);
+  file_handle = NULL;
+  file_pointer = 0;
+}
+
+static int
+is_whitespace(char ch)
+{
+  if (ch == ' ')
+    {
+      return 1;
+    }
+  if (ch == '\t')
+    {
+      return 1;
+    }
+  return 0;
+}
+
+static int
+is_eol_char(char ch)
+{
+  if (ch == '\r')
+    {
+      return 1;
+    }
+  if (ch == '\n')
+    {
+      return 1;
+    }
+  return 0;
+}
+
+static int
+is_end_of_tag(char ch)
+{
+  if ((ch >= 'a') && (ch <= 'z'))
+    {
+      return 0;
+    }
+  if ((ch >= 'A') && (ch <= 'Z'))
+    {
+      return 0;
+    }
+  if ((ch >= '0') && (ch <= '9'))
+    {
+      return 0;
+    }
+  if (ch == '_')
+    {
+      return 0;
+    }
+  return 1;
+}
+
+static int
+is_end_of_name(char ch)
+{
+  /* Currently the same as is_end_of_tag() */
+  return is_end_of_tag(ch);
+}
+
+static int
+is_valid_file(char *filename)
+{
+  char ext[MAX_PATH];
+  int i;
+
+  i = strlen(filename);
+  while (i > 0 && filename[i] != '.')
+    {
+      i--;
+    }
+  if (i > 0)
+    {
+      memset(ext, 0, sizeof(ext));
+      strncpy(&ext[0], &filename[i], strlen(&filename[i]));
+
+      if ((strncmp(ext, ".c", 2) == 0) || (strncmp(ext, ".C", 2) == 0))
+        {
+          return 1;
+        }
+    }
+  return 0;
+}
+
+static int
+get_tag_id(char *tag)
+{
+  if (strcasecmp(tag, "implemented") == 0)
+    {
+      return TAG_IMPLEMENTED;
+    }
+  if (strcasecmp(tag, "unimplemented") == 0)
+    {
+      return TAG_UNIMPLEMENTED;
+    }
+  return TAG_UNKNOWN;
+}
+
+static int
+skip_to_next_tag()
+{
+  unsigned int start;
+  int end_of_tag;
+  int found_tag = 0;
+  int tag_id;
+  int len;
+
+  tagname[0] = 0;
+  while ((file_pointer < file_size) && (!found_tag))
+    {
+      if (file_buffer[file_pointer] == '@')
+        {
+          file_pointer++;
+          start = file_pointer;
+          end_of_tag = 0;
+          while ((file_pointer < file_size) && (!end_of_tag))
+            {
+              end_of_tag = is_end_of_tag(file_buffer[file_pointer]);
+              file_pointer++;
+            }
+          len = file_pointer > start ? file_pointer - start - 1 : 0;
+          strncpy(tagname, &file_buffer[start], len);
+          tagname[len] = 0;
+
+          tag_id = get_tag_id(tagname);
+          if (tag_id != TAG_UNKNOWN)
+            {
+              return tag_id;
+            }
+        }
+      file_pointer++;
+    }
+
+  return TAG_UNKNOWN;
+}
+
+static void
+skip_line()
+{
+  while ((file_pointer < file_size) && (!is_eol_char(file_buffer[file_pointer])))
+    {
+      file_pointer++;
+    }
+  if ((file_pointer < file_size) && (file_buffer[file_pointer] == '\n'))
+    {
+      file_pointer++;
+    }
+}
+
+static void
+skip_comments()
+{
+  while ((file_pointer < file_size))
+    {
+      if (file_buffer[file_pointer] == '*')
+        {
+          if ((file_pointer + 1 < file_size))
+            {
+              if (file_buffer[file_pointer + 1] == '/')
+                {
+                  skip_line();
+                  return;
+                }
+            }
+        }
+      file_pointer++;
+    }
+}
+
+static int
+get_previous_identifier(unsigned int end, char *name)
+{
+  unsigned int my_file_pointer = end;
+  int len;
+
+  name[0] = 0;
+
+  while ((my_file_pointer > 0) && (is_whitespace(file_buffer[my_file_pointer])))
+    {
+      my_file_pointer--;
+    }
+
+  /* Skip any comments between function name and it's parameters */
+  if ((my_file_pointer > 0) && (file_buffer[my_file_pointer] == '/'))
+    {
+      if ((my_file_pointer > 0) && (file_buffer[my_file_pointer - 1] == '*'))
+        {
+          my_file_pointer--;
+          while ((my_file_pointer > 0) && !((file_buffer[my_file_pointer] == '*')
+            && (file_buffer[my_file_pointer - 1] == '/')))
+            {
+              my_file_pointer--;
+            }
+          my_file_pointer -= 2;
+        }
+    }
+
+  /* Skip any remaining whitespace */
+  while ((my_file_pointer > 0) && (is_whitespace(file_buffer[my_file_pointer])))
+    {
+      my_file_pointer--;
+    }
+
+  end = my_file_pointer;
+  while ((my_file_pointer > 0))
+    {
+      if (is_end_of_name(file_buffer[my_file_pointer]))
+        {
+          len = end - my_file_pointer;
+          strncpy(name, &file_buffer[my_file_pointer + 1], len);
+          name[len] = 0;
+          return 1;
+        }
+      my_file_pointer--;
+    }
+
+  return 0;
+}
+
+static int
+skip_to_next_name(char *name)
+{
+  while ((file_pointer < file_size))
+    {
+      if (file_buffer[file_pointer] == '(')
+        {
+          return get_previous_identifier(file_pointer - 1, name);
+        }
+      file_pointer++;
+    }
+  return 0;
+}
+
+static void
+parse_file(char *filename)
+{
+  PAPI_INFO api_info;
+  char name[200];
+  int tag_id;
+
+  read_file(filename);
+
+  do
+    {
+      tag_id = skip_to_next_tag();
+      if (tag_id == TAG_UNKNOWN)
+        {
+          break;
+        }
+
+      /* Skip rest of the comments between the tag and the function name */
+      skip_comments();
+
+      if (skip_to_next_name(name))
+        {
+          api_info = malloc(sizeof(API_INFO));
+          if (api_info == NULL)
+            {
+              printf("Out of memory\n");
+              exit(1);
+            }
+
+          api_info->tag_id = tag_id;
+          strcpy(api_info->name, name);
+
+printf("Name '%s'   File '%s'\n", name, filename);
+
+          api_info->next = api_info_list;
+          api_info_list = api_info;
+
+        }
+    } while (1);
+
+  close_file();
+}
+
+#ifdef WIN32
+
+/* Win32 version */
+static void
+process_directory (char *path)
+{
+  struct _finddata_t f;
+  int findhandle;
+  char searchbuf[MAX_PATH];
+  char buf[MAX_PATH];
+
+  printf("Processing '%s'\n", path);
+
+  strcpy(searchbuf, path);
+  strcat(searchbuf, "*.*");
+
+  findhandle =_findfirst(searchbuf, &f);
+  if (findhandle != -1)
+    {
+      do
+       {
+          if (f.attrib & _A_SUBDIR)
+           {
+              if (f.name[0] != '.')
+                {
+                  strcpy(buf, path);
+                  strcat(buf, f.name);
+                  strcat(buf, DIR_SEPARATOR_STRING);
+                  process_directory(buf);
+                }
+              continue;
+           }
+
+          strcpy(buf, path);
+          strcat(buf, f.name);
+
+          /* Must be a .c file */
+          if (!is_valid_file(buf))
+            {
+              continue;
+            }
+
+          parse_file(buf);
+       }
+      while (_findnext(findhandle, &f) == 0);
+      _findclose(findhandle);
+    }
+  else
+    {
+      printf("Cannot open directory '%s'", path);
+      exit(1);
+    }
+}
+
+#else
+
+/* Linux version */
+static void
+process_directory (char *path)
+{
+  DIR *dirp;
+  struct dirent *entry;
+  struct stat stbuf;
+  char buf[MAX_PATH];
+
+#ifdef HAVE_D_TYPE
+  dirp = opendir(path);
+  if (dirp != NULL)
+    {
+      while ((entry = readdir(dirp)) != NULL)
+        {
+          if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+            continue; // skip self and parent
+
+         if (entry->d_type == DT_REG) // normal file
+           {
+              // Check for an absolute path
+              if (path[0] == DIR_SEPARATOR_CHAR)
+                {
+                  strcpy(buf, path);
+                  strcat(buf, DIR_SEPARATOR_STRING);
+                  strcat(buf, entry->d_name);
+                }
+              else
+                {
+                  getcwd(buf, sizeof(buf));
+                  strcat(buf, DIR_SEPARATOR_STRING);
+                  strcat(buf, path);
+                  strcat(buf, entry->d_name);
+                }
+
+             if (stat(buf, &stbuf) == -1)
+                {
+                  printf("Can't access '%s' (%s)\n", buf, strerror(errno));
+                  return;
+                }
+
+              if (S_ISDIR(stbuf.st_mode))
+                   {
+                  process_directory(buf);
+                  continue;
+                   }
+
+              /* Must be a .c file */
+              if (!is_valid_file(buf))
+                {
+                  continue;
+                }
+  
+              parse_file(buf);
+           }
+      }
+      closedir(dirp);
+    }
+  else
+    {
+      printf("Can't open %s\n", path);
+      exit(1);
+    }
+
+#else
+
+  dirp = opendir(path);
+  if (dirp != NULL)
+    {
+      while ((entry = readdir(dirp)) != NULL)
+       {
+          if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+            continue; // skip self and parent
+
+          // Check for an absolute path
+          if (path[0] == DIR_SEPARATOR_CHAR)
+            {
+              strcpy(buf, path);
+              strcat(buf, DIR_SEPARATOR_STRING);
+              strcat(buf, entry->d_name);
+            }
+          else
+            {
+              getcwd(buf, sizeof(buf));
+              strcat(buf, DIR_SEPARATOR_STRING);
+              strcat(buf, path);
+              strcat(buf, entry->d_name);
+            }
+
+          if (stat(buf, &stbuf) == -1)
+            {
+              printf("Can't access '%s' (%s)\n", buf, strerror(errno));
+              return;
+            }
+
+          if (S_ISDIR(stbuf.st_mode))
+           {
+              process_directory(buf);
+              continue;
+           }
+
+          /* Must be a .c file */
+          if (!is_valid_file(buf))
+            {
+              continue;
+            }
+
+          parse_file(buf);
+        }
+      closedir(dirp);
+    }
+  else
+    {
+      printf("Can't open %s\n", path);
+      exit(1);
+    }
+
+#endif
+}
+
+#endif
+
+/*
+ * This function compares two API entries. It returns a negative value if p is
+ * before q, or a positive value if p is after q.
+ */
+static int
+compare_api_order(PAPI_INFO p, PAPI_INFO q)
+{
+  return strcmp(p->name, q->name);
+}
+
+static void
+generate_xml_for_component(char *component_name)
+{
+  PAPI_INFO api_info;
+  char buf[200];
+  int complete;
+  int total;
+  int implemented_total;
+  int unimplemented_total;
+
+  // Sort list
+  api_info_list = sort_linked_list(api_info_list, 0, compare_api_order);
+
+  implemented_total = 0;
+  unimplemented_total = 0;
+
+  api_info = api_info_list;
+  while (api_info != NULL)
+    {
+      if (api_info->tag_id == TAG_IMPLEMENTED)
+        {
+          implemented_total ++;
+        }
+      else if (api_info->tag_id == TAG_UNIMPLEMENTED)
+        {
+          unimplemented_total ++;
+        }
+
+      api_info = api_info->next;
+    }
+
+  if (implemented_total + unimplemented_total > 0)
+    {
+      complete = ((implemented_total) * 100) / (implemented_total + unimplemented_total);
+    }
+  else
+    {
+      complete = 100;
+    }
+
+  sprintf(buf, "<component name=\"%s\" complete=\"%d\" implemented_total=\"%d\" unimplemented_total=\"%d\">",
+    component_name, complete, implemented_total, unimplemented_total);
+  write_line(buf);
+
+  if (api_info_list != NULL)
+    {
+      write_line("<functions>");
+
+      api_info = api_info_list;
+      while (api_info != NULL)
+        {
+          sprintf(buf, "<function name=\"%s\" implemented=\"%s\">",
+            api_info->name, api_info->tag_id == TAG_IMPLEMENTED ? "true" : "false");
+          write_line(buf);
+          write_line("</function>");
+          api_info = api_info->next;
+        }
+
+      write_line("</functions>");
+    }
+
+  write_line("</component>");
+}
+
+static void
+read_input_file(char *input_file)
+{
+  char component_name[MAX_PATH];
+  char component_path[MAX_PATH];
+  char *canonical_path;
+  unsigned int index;
+  unsigned int start;
+  PAPI_INFO api_info;
+  PAPI_INFO next_api_info;
+  char *buffer;
+  int size;
+  int len;
+
+  in = fopen(input_file, "rb");
+  if (in == NULL)
+    {
+       printf("Cannot open input file");
+       exit(1);
+    }
+
+  // Get the size of the file
+  fseek(in, 0, SEEK_END);
+  size = ftell(in);
+
+  // Load it all into memory
+  buffer = malloc(size);
+  if (buffer == NULL)
+    {
+      fclose(in);
+      printf("Out of memory\n");
+      exit(1);
+    }
+  fseek(in, 0, SEEK_SET);
+  if (fread (buffer, 1, size, in) < 1)
+    {
+      fclose(in);
+      printf("Read error in file %s\n", input_file);
+      exit(1);
+    }
+
+  index = 0;
+
+  write_line("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");
+  write_line("");
+  write_line("<components>");
+
+  while (1)
+    {
+      /* Free previous list */
+      for (api_info = api_info_list; api_info != NULL; api_info = next_api_info)
+        {
+          next_api_info = api_info->next;
+          free(api_info);
+        }
+      api_info_list = NULL;
+
+      /* Skip whitespace and eol characters */
+      while ((index < size) && (is_whitespace(buffer[index]) || (is_eol_char(buffer[index]))))
+        {
+          index++;
+        }
+      if ((file_pointer < size) && (buffer[index] == '\n'))
+        {
+          index++;
+        }
+
+      if (buffer[index] == ';')
+        {
+          /* Skip comments */
+          while ((index < size) && (!is_eol_char(buffer[index])))
+            {
+              index++;
+            }
+          if ((index < size) && (buffer[index] == '\n'))
+            {
+              index++;
+            }
+          continue;
+        }
+
+      /* Get component name */
+      start = index;
+      while ((index < size) && (!is_whitespace(buffer[index])))
+        {
+          index++;
+        }
+      if (index >= size)
+        {
+          break;
+        }
+
+      len = index - start;
+      strncpy(component_name, &buffer[start], len);
+      component_name[len] = 0;
+
+      /* Skip whitespace */
+      while ((index < size) && (is_whitespace(buffer[index])))
+        {
+          index++;
+        }
+      if (index >= size)
+        {
+          break;
+        }
+
+      /* Get component path */
+      start = index;
+      while ((index < size) && (!is_whitespace(buffer[index]) && !is_eol_char(buffer[index])))
+        {
+          index++;
+        }
+
+      len = index - start;
+      strncpy(component_path, &buffer[start], len);
+      component_path[len] = 0;
+
+      /* Append directory separator if needed */
+      if (component_path[strlen(component_path)] != DIR_SEPARATOR_CHAR)
+        {
+          int i = strlen(component_path);
+          component_path[strlen(component_path)] = DIR_SEPARATOR_CHAR;
+          component_path[i + 1] = 0;
+        }
+
+      /* Skip to end of line */
+      while ((index < size) && (!is_eol_char(buffer[index])))
+        {
+          index++;
+        }
+      if ((index < size) && (buffer[index] == '\n'))
+        {
+          index++;
+        }
+
+      canonical_path = convert_path(component_path);
+      if (canonical_path != NULL)
+        {
+          process_directory(canonical_path);
+          free(canonical_path);
+          generate_xml_for_component(component_name);
+        }
+    }
+
+  write_line("</components>");
+}
+
+static char HELP[] =
+  "RGENSTAT  input-filename output-filename\n"
+  "\n"
+  "  input-filename   File containing list of components to process\n"
+  "  output-filename  File to create\n";
+
+int main(int argc, char **argv)
+{
+  char *input_file;
+  char *output_file;
+  int i;
+
+  if (argc < 2)
+  {
+    puts(HELP);
+    return 1;
+  }
+
+  input_file = convert_path(argv[1]);
+  if (input_file[0] == 0)
+    {
+      printf("Missing input-filename\n");
+      return 1;
+    }
+
+  output_file = convert_path(argv[2]);
+  if (output_file[0] == 0)
+    {
+      printf("Missing output-filename\n");
+      return 1;
+    }
+
+  out = fopen(output_file, "wb");
+  if (out == NULL)
+    {
+       printf("Cannot open output file");
+       return 1;
+     }
+
+  read_input_file(input_file);
+
+  fclose(out);
+
+  return 0;
+}
+
+/* EOF */
diff --git a/reactos/tools/rgenstat/web/.cvsignore b/reactos/tools/rgenstat/web/.cvsignore
new file mode 100755 (executable)
index 0000000..74a59c4
--- /dev/null
@@ -0,0 +1 @@
+apistatus.xml\r
diff --git a/reactos/tools/rgenstat/web/c.gif b/reactos/tools/rgenstat/web/c.gif
new file mode 100755 (executable)
index 0000000..08f00d4
Binary files /dev/null and b/reactos/tools/rgenstat/web/c.gif differ
diff --git a/reactos/tools/rgenstat/web/f.gif b/reactos/tools/rgenstat/web/f.gif
new file mode 100755 (executable)
index 0000000..75fe358
Binary files /dev/null and b/reactos/tools/rgenstat/web/f.gif differ
diff --git a/reactos/tools/rgenstat/web/i.gif b/reactos/tools/rgenstat/web/i.gif
new file mode 100755 (executable)
index 0000000..2c8ca54
Binary files /dev/null and b/reactos/tools/rgenstat/web/i.gif differ
diff --git a/reactos/tools/rgenstat/web/rapistatus.css b/reactos/tools/rgenstat/web/rapistatus.css
new file mode 100755 (executable)
index 0000000..52965a1
--- /dev/null
@@ -0,0 +1,52 @@
+.c IMG
+{
+       border: 0px;
+}
+
+.c, .c_,
+.f, .f_,
+.i, .i_,
+.u, .u_
+{
+       FONT: 10px 'Verdana';
+       margin-left: 20px;
+}
+
+.c_ .f,
+.c_ .f_
+{
+       display: none;
+}
+
+.t
+{
+       cursor: pointer;
+       margin-right: 8px;
+}
+
+.filter
+{
+       cursor: pointer;
+       vertical-align: middle;
+}
+
+
+.st
+{
+       margin-left: 20px;
+}
+
+.i
+{
+       margin-left: 20px;
+}
+
+.u
+{
+       margin-left: 20px;
+}
+
+.l
+{
+       cursor: pointer;
+}
diff --git a/reactos/tools/rgenstat/web/rapistatus.js b/reactos/tools/rgenstat/web/rapistatus.js
new file mode 100755 (executable)
index 0000000..55ba8c9
--- /dev/null
@@ -0,0 +1,273 @@
+function toggle (elt)
+{
+       if (elt == null)
+               return;
+
+       var eltLink = elt.firstChild;
+       if (eltLink != null && eltLink.className == 't')        // toggle
+       {
+               var ich = elt.className.indexOf ('_');
+               if (ich < 0)
+               {
+                       eltLink.src = 'tp.gif';
+                       elt.className += '_';  
+               }
+               else
+               {
+                       eltLink.src = 'tm.gif';
+                       elt.className = elt.className.slice (0, ich);
+               }
+       }
+}
+
+function setView (elt, fView)
+{
+       var eltLink = elt.firstChild;
+       if (eltLink != null && eltLink.className == 't')        // toggle
+       {
+               var ich = elt.className.indexOf ('_');
+               if (ich < 0 && !fView)
+               {
+                       eltLink.src = 'tp.gif';
+                       elt.className += '_';
+               }
+               else if (ich >= 0 && fView)
+               {
+                       eltLink.src = 'tm.gif';
+                       elt.className = elt.className.slice (0, ich);
+               }
+       }
+}
+
+function trimSrc (strSrc)
+{
+       return strSrc.slice (strSrc.lastIndexOf ('/') + 1, strSrc.lastIndexOf ('.'));
+}
+
+function getChildrenByTagName (elt, strTag)
+{
+       strTag = strTag.toLowerCase ();
+       var rgChildren = new Array ();
+       var eltChild = elt.firstChild;
+       while (eltChild)
+       {
+               if (eltChild.tagName && eltChild.tagName.toLowerCase () == strTag)
+                       rgChildren.push (eltChild);
+               eltChild = eltChild.nextSibling;
+       }
+       return rgChildren;
+}
+
+function viewAll (elt, dictTypes)
+{
+       var fView = false;
+       var rgImages = getChildrenByTagName (elt, 'IMG');
+       var cImages = rgImages.length;
+       for (var iImage = 0; iImage < cImages; iImage++)
+       {
+               var strImage = trimSrc (rgImages [iImage].src);
+               if (dictTypes [strImage])
+               {
+                       fView = true;
+                       break;
+               }
+       }
+       var rgElts = getChildrenByTagName (elt, 'DIV');
+       var cElts = rgElts.length;
+       if (cElts != 0)
+       {
+               var iElt;
+               for (iElt = 0; iElt < cElts; iElt ++)
+                       fView |= viewAll (rgElts [iElt], dictTypes);
+       }
+       elt.style.display = fView ? '' : 'none';
+       return fView;
+}
+
+function getView (elt)
+{
+       var eltLink = elt.firstChild;
+       if (eltLink != null && eltLink.className == 't')        // toggle
+       {
+               var ich = elt.className.indexOf ('_');
+               if (ich < 0)
+                       return true;
+       }
+       return false;
+}
+
+function getParentDiv (elt)
+{
+       if (elt)
+       {
+               do
+               {
+                       elt = elt.parentNode;
+               }
+               while (elt && elt.tagName != 'DIV');
+       }
+
+       return elt;
+}
+
+function getName (elt)
+{
+       var rgSpans = getChildrenByTagName (elt, 'SPAN');
+       for (var iSpan = 0; iSpan < rgSpans.length; iSpan ++)
+       {
+               var span = rgSpans [iSpan];
+               if (span.className == 'l')      // label
+               {
+                       if (span.innerText)
+                               return span.innerText;
+                       else
+                               return span.firstChild.nodeValue;
+               }
+       }
+       return null;
+}
+
+function clickHandler (evt)
+{
+       var elt;
+       if (document.layers)
+               elt = evt.taget;
+       else if (window.event && window.event.srcElement)
+       {
+               elt = window.event.srcElement;
+               evt = window.event;
+       }
+       else if (evt && evt.stopPropagation)
+               elt = evt.target;
+       
+       if (!elt.className && elt.parentNode)
+               elt = elt.parentNode;
+
+       if (elt.className == 'l')       // label
+       {
+       }
+       else
+       {
+               if (elt.parentNode && elt.parentNode.className == 't')  // toggle
+                       elt = elt.parentNode;
+               else if (elt.className != 't')  // toggle
+                       return;
+
+               while (elt != null && elt.tagName != 'DIV')
+                       elt = elt.parentNode;
+
+               if (evt.shiftKey)
+               {
+                       var rgElts = getChildrenByTagName (elt, 'DIV');
+                       var cElts = rgElts.length;
+                       if (cElts != 0)
+                       {
+                               var fView = false;
+                               var iElt;
+                               for (iElt = 0; iElt < cElts; iElt ++)
+                               {
+                                       if (getView (rgElts [iElt]))
+                                       {
+                                               fView = true;
+                                               break;
+                                       }
+                               }
+                               for (iElt = 0; iElt < cElts; iElt ++)
+                               {
+                                       setView (rgElts [iElt], !fView);
+                               }
+                       }
+               }
+               else if (evt.ctrlKey)
+               {
+                       setView (elt, true);
+                       var eltParent = getParentDiv (elt);
+                       while (eltParent)
+                       {
+                               var rgSiblings = getChildrenByTagName (eltParent, 'DIV');
+                               var cSiblings = rgSiblings.length;
+                               for (var iSibling = 0; iSibling < cSiblings; iSibling++)
+                               {
+                                       var eltSibling = rgSiblings [iSibling];
+                                       if (eltSibling != elt)
+                                       {
+                                               setView (eltSibling, false);
+                                       }
+                               }
+                               elt = eltParent;
+                               eltParent = getParentDiv (elt);
+                       }
+               }
+               else
+                       toggle (elt);
+       }
+
+       return false;
+}
+
+function filterTree ()
+{
+       var eltImplemented = document.getElementById ('implemented');
+       var eltUnimplemented = document.getElementById ('unimplemented');
+
+       var dictTypes = new Object ();
+       if (eltImplemented.checked)
+               dictTypes ['i'] = true;
+       if (eltUnimplemented.checked)
+               dictTypes ['u'] = true;
+
+       viewAll (document.getElementById ('ROOT'), dictTypes);
+}
+
+function selectImplemented ()
+{
+       toggleFilter ('implemented');
+}
+
+function selectUnimplemented ()
+{
+       toggleFilter ('unimplemented');
+}
+
+function toggleFilter (strFilter)
+{
+       var eltImplemented = document.getElementById ('implemented');
+       var eltUnimplemented = document.getElementById ('unimplemented');
+
+       var eltToggle = document.getElementById (strFilter);
+       if (window && window.event && window.event.shiftKey)
+       {
+               eltImplemented.checked = eltUnimplemented.checked;
+               eltUnimplemented.checked = true;
+       }
+       else
+       if (!eltUnimplemented.checked && !eltImplemented.checked)
+       {
+               eltImplemented.checked = eltUnimplemented.checked = true;
+               eltToggle.checked = false;
+       }
+       filterTree ();
+}
+
+function onLoad ()
+{
+       var eltImplemented = document.getElementById ('implemented');
+       var eltUnimplemented = document.getElementById ('unimplemented');
+       eltImplemented.checked = eltUnimplemented.checked = true;
+}
+
+if (document.layers)
+{
+       document.captureEvents (Event.MOUSEUP);
+       document.onmouseup = clickHandler;
+}
+else if (document.attachEvent)
+{
+       document.attachEvent('onclick', clickHandler);
+}
+else if (document.addEventListener)
+{
+       document.addEventListener('click', clickHandler, false);
+}
+else 
+       document.onclick = clickHandler;
diff --git a/reactos/tools/rgenstat/web/rapistatus.xsl b/reactos/tools/rgenstat/web/rapistatus.xsl
new file mode 100755 (executable)
index 0000000..8c6bbb7
--- /dev/null
@@ -0,0 +1,175 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+       <xsl:output method="html" indent="no"/>
+       <!--    <xsl:output method="xml"/>-->
+<!-- Will not work:    <xsl:strip-space elements="*"/> -->
+
+       <xsl:template match="/">
+               <HTML>
+                       <HEAD>
+                               <TITLE>
+                                       ReactOS API Status
+                               </TITLE>
+                               <SCRIPT src="rapistatus.js"></SCRIPT>
+                               <LINK rel="stylesheet" type="text/css" href="rapistatus.css"></LINK>
+                       </HEAD>
+                       <BODY onLoad="onLoad();">
+                               <P>
+                                       <H1>ReactOS API Status</H1>
+                               </P>
+                               <P>
+                                       <TABLE>
+                                               <TR>
+                                                       <TD> <INPUT type="checkbox" ID="implemented" onClick="selectImplemented();" checked="1"/> </TD>
+                                                       <TD> <IMG src="i.gif"/> </TD>
+                                                       <TD> Implemented </TD>
+                                                       <TD width="20"/>
+                                               </TR>
+                                               <TR>
+                                                       <TD> <INPUT type="checkbox" ID="unimplemented" onClick="selectUnimplemented();" checked="1"/> </TD>
+                                                       <TD> <IMG src="u.gif"/> </TD>
+                                                       <TD> Unimplemented </TD>
+                                                       <TD width="20"/>
+                                               </TR>
+                                       </TABLE>
+                               </P>
+                               <DIV ID="ROOT">
+                                       <xsl:apply-templates/>
+                               </DIV>
+                               <P>
+                                       Legend :<BR/>
+                                       <TABLE>
+                                               <TR>
+                                                       <TD> <IMG src="c.gif"/> </TD>
+                                                       <TD> Component </TD>
+                                                       <TD> <IMG src="i.gif"/> </TD>
+                                                       <TD> Implemented </TD>
+                                                       <TD> <IMG src="sc.gif"/> </TD>
+                                                       <TD> Complete </TD>
+                                               <TR>
+                                               </TR>
+                                                       <TD> <IMG src="f.gif"/> </TD>
+                                                       <TD> Function </TD>
+                                                       <TD> <IMG src="u.gif"/> </TD>
+                                                       <TD> Unimplemented </TD>
+                                                       <TD></TD>
+                                                       <TD></TD>
+                                               </TR>
+                                       </TABLE>
+
+                               </P>
+                       </BODY>
+               </HTML>
+       </xsl:template>
+
+
+       <!-- component -->
+       <xsl:template match="/components">
+               <xsl:apply-templates select="component">
+                       <xsl:sort select="@name"/>
+               </xsl:apply-templates>
+       </xsl:template>
+
+       <xsl:template match="components/component[@implemented_total or @unimplemented_total]">
+               <DIV>
+                       <xsl:call-template name="ELEMENT">
+                               <xsl:with-param name="class">c</xsl:with-param>
+                       </xsl:call-template>
+                       <xsl:apply-templates/>
+               </DIV>
+       </xsl:template>
+
+
+       <!-- function -->
+       <xsl:template match="functions">
+               <xsl:apply-templates select="function">
+                       <xsl:sort select="@name"/>
+               </xsl:apply-templates>
+       </xsl:template>
+
+       <xsl:template match="functions/function">
+               <DIV>
+                       <xsl:call-template name="ELEMENT">
+                               <xsl:with-param name="class">f</xsl:with-param>
+                       </xsl:call-template>
+                       <xsl:apply-templates/>
+               </DIV>
+       </xsl:template>
+
+
+       <!-- support templates -->
+
+       <xsl:template name="ELEMENT">
+               <xsl:param name="class"/>
+               <xsl:param name="image"/>
+                       <xsl:attribute name="class">
+                       <xsl:value-of select="$class"/>
+                       <xsl:text>_</xsl:text>
+                       </xsl:attribute>
+                       <xsl:call-template name="toggle"/>
+                       <xsl:choose>
+                               <xsl:when test="./node() and local-name() != 'component' and @implemented = 'true'">
+          <img src="i.gif" class="i"/>
+                               </xsl:when>
+                               <xsl:when test="./node() and local-name() != 'component' and @implemented = 'false'">
+          <img src="u.gif" class="u"/>
+                               </xsl:when>
+                               <xsl:when test="./node() and local-name() = 'component' and @complete >= 100">
+          <img src="sc.gif"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+          <img src="tb.gif" with="12" height="12"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       <xsl:choose>
+                               <xsl:when test="$image">
+                                       <img src="{$image}.gif" class="t"/>
+                               </xsl:when>
+                               <xsl:otherwise>
+                                       <img src="{$class}.gif" class="t"/>
+                               </xsl:otherwise>
+                       </xsl:choose>
+                       <xsl:call-template name="name"/>
+                       <xsl:call-template name="status"/>
+       </xsl:template>
+
+       <xsl:template name="status">
+               <xsl:if test="@complete and @complete != 0">
+                       <SPAN class="st">
+                               <img src="sc.gif"/>
+                               <xsl:text>: </xsl:text>
+                               <xsl:value-of select="@complete"/>
+                               <xsl:text>%</xsl:text>
+                       </SPAN>
+               </xsl:if>
+               <xsl:if test="@implemented_total">
+                       <SPAN class="st">
+                               <img src="i.gif"/>: <xsl:value-of select="@implemented_total"/>
+                       </SPAN>
+               </xsl:if>
+               <xsl:if test="@unimplemented_total">
+                       <SPAN class="st">
+                               <img src="u.gif"/>: <xsl:value-of select="@unimplemented_total"/>
+                       </SPAN>
+               </xsl:if>
+       </xsl:template>
+
+       <xsl:template name="toggle">
+               <xsl:choose>
+                       <xsl:when test="local-name() = 'component'">
+                               <IMG src="tp.gif" class="t"/>
+                       </xsl:when>
+                       <xsl:otherwise>
+                       <IMG src="tb.gif"/>
+                       </xsl:otherwise>
+               </xsl:choose>
+       </xsl:template>
+
+       <xsl:template name="name">
+               <xsl:if test="@name">
+                       <SPAN class="l"><xsl:value-of select="@name"/></SPAN>
+               </xsl:if>
+       </xsl:template>
+
+</xsl:stylesheet>
diff --git a/reactos/tools/rgenstat/web/sc.gif b/reactos/tools/rgenstat/web/sc.gif
new file mode 100755 (executable)
index 0000000..b02afd9
Binary files /dev/null and b/reactos/tools/rgenstat/web/sc.gif differ
diff --git a/reactos/tools/rgenstat/web/tb.gif b/reactos/tools/rgenstat/web/tb.gif
new file mode 100755 (executable)
index 0000000..ee68c5a
Binary files /dev/null and b/reactos/tools/rgenstat/web/tb.gif differ
diff --git a/reactos/tools/rgenstat/web/tm.gif b/reactos/tools/rgenstat/web/tm.gif
new file mode 100755 (executable)
index 0000000..3c8f18a
Binary files /dev/null and b/reactos/tools/rgenstat/web/tm.gif differ
diff --git a/reactos/tools/rgenstat/web/tp.gif b/reactos/tools/rgenstat/web/tp.gif
new file mode 100755 (executable)
index 0000000..8b74353
Binary files /dev/null and b/reactos/tools/rgenstat/web/tp.gif differ
diff --git a/reactos/tools/rgenstat/web/u.gif b/reactos/tools/rgenstat/web/u.gif
new file mode 100755 (executable)
index 0000000..0c71947
Binary files /dev/null and b/reactos/tools/rgenstat/web/u.gif differ