diff --git a/reactos/ChangeLog b/reactos/ChangeLog
index 110dbc5c1d4..da5a36e691e 100644
--- a/reactos/ChangeLog
+++ b/reactos/ChangeLog
@@ -1,3 +1,20 @@
+2003-07-10 Casper S. Hornstrup
+
+ * 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
* 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
index 00000000000..fa11faec13b
--- /dev/null
+++ b/reactos/apistatus.lst
@@ -0,0 +1,30 @@
+; Format:
+; COMPONENT_NAME PATH_TO_COMPONENT_SOURCES
+; COMPONENT_NAME - Name of the component. Eg. kernel32.dll.
+; PATH_TO_COMPONENT_SOURCES - Relative path to sources (relative to
+; where rgenstat is run from).
+advapi32.dll reactos/lib/advapi32
+crtdll.dll reactos/lib/crtdll
+gdi32.dll reactos/lib/gdi32
+iphlpapi.dll reactos/lib/iphlpapi
+kernel32.dll reactos/lib/kernel32
+msvcrt.dll reactos/lib/msvcrt
+ole32.dll reactos/lib/ole32
+oleaut32.dll reactos/lib/oleaut32
+rpcrt4.dll reactos/lib/rpcrt4
+secur32.dll reactos/lib/secur32
+shell32.dll reactos/lib/shell32
+snmpapi.dll reactos/lib/snmpapi
+user32.dll reactos/lib/user32
+version.dll reactos/lib/version
+winmm.dll reactos/lib/winmm
+winspool.dll reactos/lib/winspool
+ws2_32.dll reactos/lib/ws2_32
+wsock32.dll reactos/lib/wsock32
+videoprt.dll reactos/drivers/dd/videoprt
+ndis.dll reactos/drivers/net/ndis
+tdi.dll reactos/drivers/net/tdi
+class2.sys reactos/drivers/storage/class2
+scsiport.sys reactos/drivers/storage/scsiport
+ntoskrnl.exe reactos/ntoskrnl
+win32k.sys reactos/subsys/win32k
diff --git a/reactos/rules.mak b/reactos/rules.mak
index d91f330e7a6..8db52b399bd 100644
--- a/reactos/rules.mak
+++ b/reactos/rules.mak
@@ -95,6 +95,7 @@ RMKDIR = $(TOOLS_PATH)/rmkdir
RSYM = $(TOOLS_PATH)/rsym
RTOUCH = $(TOOLS_PATH)/rtouch
MC = $(TOOLS_PATH)/wmc/wmc
+XSLTPROC = xsltproc
# Maybe we can delete these soon
diff --git a/reactos/tools/Makefile b/reactos/tools/Makefile
index c38b40ab038..39f73f44b14 100644
--- a/reactos/tools/Makefile
+++ b/reactos/tools/Makefile
@@ -14,7 +14,7 @@ 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
@@ -99,12 +99,18 @@ cdmake_target:
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
+ $(MAKE) -C rgenstat clean
rm mkconfig
rm $(TOOLS)
endif
@@ -113,6 +119,7 @@ clean:
$(MAKE) -C cdmake clean
$(MAKE) -C mkhive clean
$(MAKE) -C wmc clean
+ $(MAKE) -C rgenstat clean
del *$(EXE_POSTFIX)
endif
diff --git a/reactos/tools/rgenstat/.cvsignore b/reactos/tools/rgenstat/.cvsignore
new file mode 100755
index 00000000000..75f1ce11793
--- /dev/null
+++ b/reactos/tools/rgenstat/.cvsignore
@@ -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
index 00000000000..4d5291c7357
--- /dev/null
+++ b/reactos/tools/rgenstat/Makefile
@@ -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
index 00000000000..b9011755246
--- /dev/null
+++ b/reactos/tools/rgenstat/llmosrt.c
@@ -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
+
+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
index 00000000000..5e278cb8de5
--- /dev/null
+++ b/reactos/tools/rgenstat/rgenstat.c
@@ -0,0 +1,870 @@
+/*
+ * Generate a file with API status information from a list
+ * of files in a directory.
+ * Casper S. Hornstrup
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef WIN32
+#include
+#include
+#else
+#include
+#include
+#include
+#include
+#endif
+#include
+#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, complete, implemented_total, unimplemented_total);
+ write_line(buf);
+
+ if (api_info_list != NULL)
+ {
+ write_line("");
+
+ api_info = api_info_list;
+ while (api_info != NULL)
+ {
+ sprintf(buf, "",
+ api_info->name, api_info->tag_id == TAG_IMPLEMENTED ? "true" : "false");
+ write_line(buf);
+ write_line("");
+ api_info = api_info->next;
+ }
+
+ write_line("");
+ }
+
+ write_line("");
+}
+
+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("");
+ write_line("");
+ write_line("");
+
+ 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("");
+}
+
+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
index 00000000000..74a59c46349
--- /dev/null
+++ b/reactos/tools/rgenstat/web/.cvsignore
@@ -0,0 +1 @@
+apistatus.xml
diff --git a/reactos/tools/rgenstat/web/c.gif b/reactos/tools/rgenstat/web/c.gif
new file mode 100755
index 00000000000..08f00d4ea11
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
index 00000000000..75fe3586d48
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
index 00000000000..2c8ca547929
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
index 00000000000..52965a119c0
--- /dev/null
+++ b/reactos/tools/rgenstat/web/rapistatus.css
@@ -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
index 00000000000..55ba8c976e7
--- /dev/null
+++ b/reactos/tools/rgenstat/web/rapistatus.js
@@ -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
index 00000000000..8c6bbb74506
--- /dev/null
+++ b/reactos/tools/rgenstat/web/rapistatus.xsl
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+ ReactOS API Status
+
+
+
+
+
+
+
ReactOS API Status
+
+
+
+
+
+
+
+
+ Legend :
+
+
+ |
+ Component |
+ |
+ Implemented |
+ |
+ Complete |
+
+
+ |
+ Function |
+ |
+ Unimplemented |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ c
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ f
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :
+
+ %
+
+
+
+
+
:
+
+
+
+
+
:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reactos/tools/rgenstat/web/sc.gif b/reactos/tools/rgenstat/web/sc.gif
new file mode 100755
index 00000000000..b02afd9b2e0
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
index 00000000000..ee68c5a356b
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
index 00000000000..3c8f18aecea
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
index 00000000000..8b7435361b7
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
index 00000000000..0c7194786d5
Binary files /dev/null and b/reactos/tools/rgenstat/web/u.gif differ