]> git.8kb.co.uk Git - dataflex/df32func/commitdiff
Initial import
authorglyn <glyn@8kb.co.uk>
Thu, 9 Apr 2009 20:58:10 +0000 (21:58 +0100)
committerglyn <glyn@8kb.co.uk>
Thu, 9 Apr 2009 20:58:10 +0000 (21:58 +0100)
26 files changed:
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
build.bat [new file with mode: 0644]
src/c/Makefile [new file with mode: 0644]
src/c/README [new file with mode: 0644]
src/c/df32func.c [new file with mode: 0644]
src/c/df32func.h [new file with mode: 0644]
src/c/df32func.rc [new file with mode: 0644]
src/df32/console.h [new file with mode: 0644]
src/df32/console.inc [new file with mode: 0644]
src/df32/data.inc [new file with mode: 0644]
src/df32/date.inc [new file with mode: 0644]
src/df32/depmacro.inc [new file with mode: 0644]
src/df32/df32func.inc.autodoc [new file with mode: 0644]
src/df32/df32func.mk [new file with mode: 0644]
src/df32/encode.h [new file with mode: 0644]
src/df32/encode.inc [new file with mode: 0644]
src/df32/errors.h [new file with mode: 0644]
src/df32/hash.inc [new file with mode: 0644]
src/df32/macro.inc [new file with mode: 0644]
src/df32/math.inc [new file with mode: 0644]
src/df32/string.inc [new file with mode: 0644]
src/df32/tcpcomm.h [new file with mode: 0644]
src/df32/tstamp.inc [new file with mode: 0644]
src/df32/win32.h [new file with mode: 0644]
src/df32/win32.inc [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..fafff2e
--- /dev/null
@@ -0,0 +1,2 @@
+.DS_Store
+Thumbs.db
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..4ddfd28
--- /dev/null
+++ b/README.md
@@ -0,0 +1,40 @@
+df32func\r
+========\r
+Some useful helper functions to speed up development when working with DataFlex\r
+3.2 console mode.\r
+\r
+Requirements\r
+------------\r
+MinGW or compatible GNU C compiler: http://www.mingw.org/\r
+DataFlex 3.2 Console Mode or greater: http://www.dataaccess.com/\r
+\r
+Installation\r
+------------\r
+Ensure you have both DF32 and MinGW environments set up correctly and have both \r
+bin directories are in your path (i.e. locations of "dfcomp" and "make")\r
+\r
+Open a DOS prompt and cd into df32func directory.\r
+\r
+To build the dynamic link library and the dataflex precompiled package:\r
+\r
+       build all\r
+\r
+To build just the dataflex precompiled package:\r
+\r
+       build df\r
+\r
+Or build each independently\r
+\r
+The dynamic link library:\r
+\r
+       cd src/c\r
+       make clean\r
+       make\r
+\r
+The dataflex precompiled package:\r
+\r
+       cd src/df32\r
+       dfcomp df32func.mk -p\r
+       \r
+Alternatively include the dataflex includes as required directly in dataflex\r
+source code.
diff --git a/build.bat b/build.bat
new file mode 100644 (file)
index 0000000..4879521
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,107 @@
+@echo off\r
+\r
+set LC1=%1\r
+set LC1=%LC1:A=a%\r
+set LC1=%LC1:B=b%\r
+set LC1=%LC1:C=c%\r
+set LC1=%LC1:D=d%\r
+set LC1=%LC1:E=e%\r
+set LC1=%LC1:F=f%\r
+set LC1=%LC1:G=g%\r
+set LC1=%LC1:H=h%\r
+set LC1=%LC1:I=i%\r
+set LC1=%LC1:J=j%\r
+set LC1=%LC1:K=k%\r
+set LC1=%LC1:L=l%\r
+set LC1=%LC1:M=m%\r
+set LC1=%LC1:N=n%\r
+set LC1=%LC1:O=o%\r
+set LC1=%LC1:P=p%\r
+set LC1=%LC1:Q=q%\r
+set LC1=%LC1:R=r%\r
+set LC1=%LC1:S=s%\r
+set LC1=%LC1:T=t%\r
+set LC1=%LC1:U=u%\r
+set LC1=%LC1:V=v%\r
+set LC1=%LC1:W=w%\r
+set LC1=%LC1:X=x%\r
+set LC1=%LC1:Y=y%\r
+set LC1=%LC1:Z=z%\r
+\r
+if A%LC1%A == AdebugA goto do_debug\r
+if A%LC1%A == AallA goto do_all\r
+if A%LC1%A == AdfA goto do_df\r
+if A%LC1%A == AcleanA goto do_clean\r
+goto unknown\r
+\r
+:do_clean\r
+    @echo MAKE: Cleaning for df32func dll library\r
+    cd src\c\r
+    if %errorlevel% == 0 goto cclean\r
+    @echo Can't cd to directory (Error level %errorlevel%)\r
+    goto errors \r
+    :cclean\r
+    make clean\r
+    cd ..\..\r
+    @echo DEL: Cleaning for df32func DataFlex precompiled package\r
+    cd src\df32\r
+    del df32func.flp df32func.pki\r
+    cd ..\..\r
+    goto do_exit\r
+:do_all\r
+    @echo MAKE: Compiling df32func dll library\r
+    cd src\c\r
+    if %errorlevel% == 0 goto cmake\r
+    @echo Can't cd to directory (Error level %errorlevel%)\r
+    goto errors \r
+    :cmake\r
+    make clean\r
+    make\r
+    if %errorlevel% == 0 goto okayc\r
+    @echo Errors occoured during compile for df32func.dll (Error level %errorlevel%)\r
+    goto errors\r
+    :okayc\r
+    cd ..\..\r
+:do_df \r
+    @echo DFCOMP: Compiling df32func DataFlex precompiled package\r
+    cd src\df32\r
+    if %errorlevel% == 0 goto dfmake\r
+    @echo Can't cd to directory (Error level %errorlevel%)\r
+    goto errors \r
+    :dfmake\r
+    dfcomp df32func.mk -p\r
+    if %errorlevel% == 0 goto okaydf\r
+    @echo Errors occoured during compile for df32func.flp (Error level %errorlevel%)\r
+    goto errors\r
+    :okaydf   \r
+    @echo df32func.inc last compiled on %date% at %time% > df32func.inc.autodoc\r
+    @echo df32func DLL functions: >> df32func.inc.autodoc\r
+    findstr /s /i /b "external_function" *.* >> df32func.inc.autodoc\r
+    @echo df32func functions: >> df32func.inc.autodoc\r
+    findstr /s /i /b "function " *.* >> df32func.inc.autodoc\r
+    @echo df32func procedures: >> df32func.inc.autodoc\r
+    findstr /s /i /b "procedure " *.* >> df32func.inc.autodoc    \r
+    @echo df32func classes: >> df32func.inc.autodoc\r
+    findstr /s /i /b "class " *.* >> df32func.inc.autodoc\r
+    cd ..\..\r
+    goto do_exit\r
+:do_debug\r
+    @echo DFCOMP: Compiling df32func DataFlex debug package df32fdbg.mk\r
+    del df32fdbg.mk\r
+    copy df32func.mk df32fdbg.mk\r
+    dfcomp df32fdbg.mk -p -f\r
+    goto do_exit\r
+\r
+:unknown\r
+@echo Unknown action: "%LC1%"\r
+exit /B\r
+\r
+:errors\r
+@echo Compilation failed: see above for detail\r
+exit /B\r
+\r
+:do_exit\r
+@echo Compilation completed successfully\r
+exit /B\r
+\r
+\r
diff --git a/src/c/Makefile b/src/c/Makefile
new file mode 100644 (file)
index 0000000..7806731
--- /dev/null
@@ -0,0 +1,30 @@
+# Project: df32func\r
+\r
+CC   = gcc.exe\r
+WINDRES = windres.exe\r
+RES  = df32func.res\r
+OBJ  = df32func.o $(RES)\r
+LINKOBJ  = df32func.o $(RES)\r
+LIBS =  --no-export-all-symbols --add-stdcall-alias -lwsock32  \r
+BIN  = df32func.dll\r
+CFLAGS = -O2\r
+DLLWRAP=dllwrap.exe\r
+DEFFILE=libdf32func.def\r
+STATICLIB=libdf32func.a\r
+RM = del -f\r
+\r
+.PHONY: all all-before all-after clean clean-custom\r
+\r
+all: all-before df32func.dll all-after\r
+\r
+clean: clean-custom\r
+       ${RM} $(OBJ) $(BIN) $(RES) $(DEFFILE) $(STATICLIB)\r
+\r
+$(BIN): $(LINKOBJ)\r
+       $(DLLWRAP) --output-def $(DEFFILE) --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN)\r
+\r
+df32func.o: df32func.c\r
+       $(CC) -c df32func.c -o df32func.o $(CFLAGS)\r
+\r
+df32func.res: df32func.rc \r
+       $(WINDRES) -i df32func.rc --input-format=rc -o $(RES) -O coff \r
diff --git a/src/c/README b/src/c/README
new file mode 100644 (file)
index 0000000..10ad178
--- /dev/null
@@ -0,0 +1,6 @@
+Building\r
+========\r
+\r
+Use MinGW:\r
+    make clean\r
+    make
\ No newline at end of file
diff --git a/src/c/df32func.c b/src/c/df32func.c
new file mode 100644 (file)
index 0000000..6b221c4
--- /dev/null
@@ -0,0 +1,223 @@
+/*-------------------------------------------------------------------------\r
+ * df32func.c\r
+ *     df32func extensions for Console Mode DataFlex 3.2\r
+ *\r
+ * Copyright (c) 2007-2009, glyn@8kb.co.uk\r
+ * Author: Glyn Astill <glyn@8kb.co.uk>\r
+ *\r
+ *-------------------------------------------------------------------------\r
+ */\r
+\r
+#include "df32func.h"\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <winsock.h>\r
+\r
+SOCKET s, sc; /* Socket handle */\r
+\r
+/*\r
+ * The number of cycles used by the processor since the start obtained on x86\r
+ * processors (Intel, AMD), with the assembly command rdtsc.\r
+ */\r
+int rdtsc()\r
+{\r
+    __asm__ __volatile__("rdtsc");\r
+}\r
+\r
+/*\r
+ * CLIENTSOCKET \96 Creates a communication socket and connects to a remote host on the\r
+ *                supplied port and IP\r
+ */\r
+DLLIMPORT int ClientSocket(int PortNo, char* IPAddress){\r
+    /* Start up Winsock */\r
+    WSADATA wsadata;\r
+\r
+    int error = WSAStartup(0x0202, &wsadata);\r
+\r
+    /* Did something happen? */\r
+    if (error){\r
+        return -1;\r
+    }\r
+\r
+    /* Did we get the right Winsock version? */\r
+    if (wsadata.wVersion != 0x0202){\r
+        WSACleanup(); /* Clean up Winsock */\r
+        return -1;\r
+    }\r
+\r
+    /* Fill out the information needed to initialize a socket */\r
+    SOCKADDR_IN target; /* Socket address information */\r
+\r
+    target.sin_family = AF_INET; /*  address family Internet */\r
+    target.sin_port = htons (PortNo); /* Port to connect on */\r
+    target.sin_addr.s_addr = inet_addr (IPAddress); /* Target IP */\r
+\r
+    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); /* Create socket */\r
+    if (s == INVALID_SOCKET){\r
+        return -1; /* Couldn't create the socket */\r
+    }\r
+\r
+    /* Try connecting */\r
+    if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR){\r
+        return -1; /* Couldn't connect */\r
+    }\r
+    else{\r
+        return s; /* Success - return our socket number */\r
+    }\r
+}\r
+\r
+/*\r
+ * SERVERSOCKET \96 Creates a communication socket and a tcp server listening on a the\r
+ *                supplied port number\r
+ */\r
+DLLIMPORT int ServerSocket(int PortNo){\r
+    /* Start up Winsock */\r
+    WSADATA wsadata;\r
+\r
+    int error = WSAStartup(0x0202, &wsadata);\r
+\r
+    /* Did something happen? */\r
+    if (error){\r
+        return -1;\r
+    }\r
+\r
+    /* Did we get the right Winsock version? */\r
+    if (wsadata.wVersion != 0x0202){\r
+        WSACleanup(); /* Clean up Winsock */\r
+        return -1;\r
+    }\r
+\r
+    /* Fill out the information needed to initialize a socket */\r
+    SOCKADDR_IN target; /* Socket address information */\r
+\r
+    target.sin_family = AF_INET; /*  address family Internet */\r
+    target.sin_port = htons (PortNo); /* Port to connect on */\r
+    target.sin_addr.s_addr = INADDR_ANY; /* Target IP */\r
+\r
+    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); /* Create socket */\r
+    if (s == INVALID_SOCKET){\r
+        return -1; /* Couldn't create the socket */\r
+    }\r
+\r
+    /* Try to bind to the socket */\r
+    if (bind(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR) {\r
+        return -1; /* Couldn't connect */\r
+    }\r
+    else{\r
+         /* Now we can start listening, We allow SOMNAXCONN connections. This will not return until we get a connection */\r
+         if (listen(s, SOMAXCONN) == SOCKET_ERROR) {\r
+                       return -1;\r
+         }\r
+         else{\r
+              return s;\r
+         }\r
+    }\r
+}\r
+\r
+/*\r
+ * CLOSECONNECTION \96 shuts down a communication socket and closes any connection on it\r
+ */\r
+DLLIMPORT void CloseConnection (int socket){\r
+    /* Close the socket if it exists */\r
+    if (socket){\r
+        closesocket(socket);\r
+    }\r
+\r
+    WSACleanup(); /* Clean up Winsock */\r
+}\r
+\r
+/*\r
+ * SEND - Send data over the communication socket\r
+ */\r
+DLLIMPORT int Send(int socket, char* data){\r
+         return send(socket, data, strlen(data), 0);\r
+}\r
+\r
+/*\r
+ * RECEIVE - Recieve data over the client socket\r
+ */\r
+DLLIMPORT int Receive(int socket, char *pData){\r
+       char data[255] = {0};\r
+       int bytesIn = 0;\r
+\r
+       memset(data, 0, sizeof(data));\r
+       bytesIn = recv(socket, data, sizeof(data), 0);\r
+       if (bytesIn == SOCKET_ERROR) {\r
+                  return -1;\r
+       }\r
+       sprintf (pData, "%s", data );\r
+       return bytesIn;\r
+}\r
+\r
+/*\r
+ * ACCEPTCLIENT - Accept a client connection\r
+ */\r
+DLLIMPORT int AcceptClient(){\r
+       SOCKADDR_IN client;\r
+       int clientSize = sizeof(client);\r
+       sc = accept(s, (SOCKADDR *)&client, &clientSize);\r
+       if (sc == INVALID_SOCKET){\r
+              return -1;\r
+      }\r
+      return sc;\r
+}\r
+\r
+/*\r
+ * Generate a pseudo random integer from an integer\r
+ */\r
+DLLIMPORT unsigned int PseudoRand(unsigned int w){\r
+       unsigned int m_w = w;\r
+       unsigned int m_z = (w / 2);\r
+\r
+       m_z = 36969 * (m_z & 65535) + (m_z >> 16);\r
+       m_w = 18000 * (m_w & 65535) + (m_w >> 16);\r
+       return (m_z << 16) + m_w;  /* 32-bit result */\r
+}\r
+\r
+/*\r
+ * Generate a random integer from the cpu rdtsc\r
+ */\r
+DLLIMPORT unsigned int RdtscRand(){\r
+     unsigned int n = 0;\r
+     int i;\r
+     /*  First digit must be non-zero: */\r
+     do\r
+     {\r
+            srand(rdtsc());\r
+            n = rand() % 8;\r
+     } while(n == 0);\r
+     for(i = 1; i < 8; i++)\r
+     {\r
+            n *= 8;\r
+            srand(rdtsc());\r
+            n += rand() % 8;\r
+     }\r
+     return n;\r
+}\r
+\r
+/*\r
+ * DLL entry point\r
+ */\r
+BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,\r
+                       DWORD reason        /* Reason this function is being called. */ ,\r
+                       LPVOID reserved     /* Not used. */ )\r
+{\r
+    switch (reason)\r
+    {\r
+      case DLL_PROCESS_ATTACH:\r
+        break;\r
+\r
+      case DLL_PROCESS_DETACH:\r
+        break;\r
+\r
+      case DLL_THREAD_ATTACH:\r
+        break;\r
+\r
+      case DLL_THREAD_DETACH:\r
+        break;\r
+    }\r
+\r
+    /* Returns TRUE on success, FALSE on failure */\r
+    return TRUE;\r
+}\r
diff --git a/src/c/df32func.h b/src/c/df32func.h
new file mode 100644 (file)
index 0000000..7460c62
--- /dev/null
@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------\r
+ * df32func.h\r
+ *     df32func extension definitions\r
+ *\r
+ * Copyright (c) 2007-2009, glyn@8kb.co.uk\r
+ * Author: Glyn Astill <glyn@8kb.co.uk>\r
+ *\r
+ *-------------------------------------------------------------------------\r
+ */\r
+\r
+#ifndef _DF32FUNC_H_\r
+#define _DF32FUNC_H_\r
+\r
+#define DLLIMPORT __declspec (dllexport)\r
+\r
+DLLIMPORT void CloseConnection(int socket);\r
+DLLIMPORT int ClientSocket(int PortNo, char* IPAddress);\r
+DLLIMPORT int Send(int socket, char* data);\r
+DLLIMPORT int Receive(int socket, char *pData);\r
+DLLIMPORT int ServerSocket(int PortNo);\r
+DLLIMPORT int AcceptClient();\r
+DLLIMPORT unsigned int PseudoRand(unsigned int w);\r
+DLLIMPORT unsigned int RdtscRand();\r
+\r
+#endif /* _DF32FUNC_H_ */\r
diff --git a/src/c/df32func.rc b/src/c/df32func.rc
new file mode 100644 (file)
index 0000000..5c614b2
--- /dev/null
@@ -0,0 +1,28 @@
+#include <windows.h> // include for version info constants\r
+\r
+1 VERSIONINFO\r
+FILEVERSION 0,1,1,1\r
+PRODUCTVERSION 0,1,1,1\r
+FILETYPE VFT_DLL\r
+{\r
+  BLOCK "StringFileInfo"\r
+        {\r
+                BLOCK "080904E4"\r
+                {\r
+                        VALUE "CompanyName", "8kb.co.uk"\r
+                        VALUE "FileVersion", "0.1.1.1"\r
+                        VALUE "FileDescription", "df32func extensions for Console Mode DataFlex 3.2"\r
+                        VALUE "InternalName", "DF32FUNC"\r
+                        VALUE "LegalCopyright", "Copyright Â© Glyn Astill 2007"\r
+                        VALUE "LegalTrademarks", "Glyn Astill, 8kb.co.uk"\r
+                        VALUE "OriginalFilename", "df32func.dll"\r
+                        VALUE "ProductName", "df32func"\r
+                        VALUE "ProductVersion", "0.1.1.1"\r
+                }\r
+        }\r
+  BLOCK "VarFileInfo"\r
+        {\r
+                VALUE "Translation", 0x0809, 1252\r
+        }\r
+}\r
+\r
diff --git a/src/df32/console.h b/src/df32/console.h
new file mode 100644 (file)
index 0000000..9e56ea1
--- /dev/null
@@ -0,0 +1,62 @@
+//-------------------------------------------------------------------------
+// console.h
+//      This file contains definitions "font maps" used to draw large chars
+//
+// This file is to be included when using bigText in df32func.mk
+//
+// Copyright (c) 2006-2009, glyn@8kb.co.uk
+// 
+// df32func/console.h
+//-------------------------------------------------------------------------
+
+Define __console_h__
+
+//-------------------------------------------------------------------------
+// Global objects
+//-------------------------------------------------------------------------            
+
+// Global array used to store "font map" for large text
+object font_array is an array
+end_object
+
+set array_value of (font_array(current_object)) item (ascii("0")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("1")) to "0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0"
+set array_value of (font_array(current_object)) item (ascii("2")) to "1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("3")) to "1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("4")) to "1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("5")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("6")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("7")) to "1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("8")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("9")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("A")) to "0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("B")) to "1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0"
+set array_value of (font_array(current_object)) item (ascii("C")) to "0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("D")) to "1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0"
+set array_value of (font_array(current_object)) item (ascii("E")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("F")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("G")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("H")) to "1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("I")) to "1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("J")) to "0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("K")) to "1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("L")) to "1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("M")) to "1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1"
+set array_value of (font_array(current_object)) item (ascii("N")) to "1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("O")) to "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("P")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("Q")) to "1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0"
+set array_value of (font_array(current_object)) item (ascii("R")) to "1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("S")) to "0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0"
+set array_value of (font_array(current_object)) item (ascii("T")) to "1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("U")) to "1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("V")) to "1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("W")) to "1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("X")) to "1,1,0,0,0,0,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1"
+set array_value of (font_array(current_object)) item (ascii("Y")) to "1,1,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("Z")) to "1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1"
+set array_value of (font_array(current_object)) item (ascii("%")) to "1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,1,1"
+set array_value of (font_array(current_object)) item (ascii("ø")) to "0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+set array_value of (font_array(current_object)) item (ascii(".")) to "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("-")) to "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
+set array_value of (font_array(current_object)) item (ascii("+")) to "0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0"
diff --git a/src/df32/console.inc b/src/df32/console.inc
new file mode 100644 (file)
index 0000000..75c8c42
--- /dev/null
@@ -0,0 +1,217 @@
+//-------------------------------------------------------------------------\r
+// console.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to manipulate console window.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/console.inc\r
+//-------------------------------------------------------------------------\r
+\r
+#IFDEF __console_h__\r
+#ELSE\r
+    #INCLUDE console.h\r
+#ENDIF\r
+\r
+//-------------------------------------------------------------------------\r
+// Global objects\r
+//-------------------------------------------------------------------------            \r
+\r
+// Global StringTokenizer used to store "font blocks" for large text\r
+object font_split is a StringTokenizer\r
+end_object\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Set the display mode to argv lines\r
+function set_mode global integer argv returns integer\r
+    local string l_01tmpStr\r
+\r
+    if (sysconf(sysconf_os_name)) eq "Win32 Console Mode" move "c:\windows\system32\mode con: cols=80 lines=" to l_01tmpStr\r
+    if (sysconf(sysconf_os_name)) ne "Win32 Console Mode" move "c:\windows\command\mode con: cols=80 lines=" to l_01tmpStr\r
+\r
+    append l_01tmpStr argv\r
+    runprogram wait l_01tmpStr\r
+\r
+    function_return 0\r
+end_function\r
+\r
+// Display a text file to screen\r
+function screen_display global string argv returns integer\r
+    local string l_sBuf l_k l_sTmp\r
+    local integer l_i l_iLineAt l_iTotalLines l_iTotalWidth l_iWidthAt\r
+\r
+    // Add color markup here.    \r
+    move 1 to l_iWidthAt\r
+    move 0 to l_iLineAt\r
+    move 0 to l_iTotalLines\r
+    move 0 to l_iTotalWidth\r
+\r
+    direct_input channel default_file_channel argv   \r
+    while not (seqeof)\r
+        readln channel default_file_channel l_sBuf\r
+        move (rtrim(l_sBuf)) to l_sbuf\r
+        move (replaces("{YELLOW}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{WHITE}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{RED}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{GREEN}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{BLUE}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{PURPLE}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{GREY}",l_sBuf,"")) to l_sBuf\r
+        move (replaces("{BLACK}",l_sBuf,"")) to l_sBuf\r
+        if (length(l_sBuf) > l_iTotalWidth) move ((length(l_sBuf))+1) to l_iTotalWidth\r
+        increment l_iTotalLines\r
+    loop\r
+    close_input channel default_file_channel \r
+\r
+    while not (key.escape)\r
+        direct_input channel default_file_channel argv\r
+            for l_i from 1 to l_iLineAt\r
+                readln channel default_file_channel \r
+            loop\r
+            for l_i from 1 to 22\r
+                readln channel default_file_channel l_sBuf\r
+                gotoxy (l_i-1) 0\r
+\r
+                    if (uppercase(l_sBuf) contains "{YELLOW}") begin\r
+                        move (replaces("{YELLOW}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 1\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{WHITE}") begin\r
+                        move (replaces("{WHITE}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 2\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{RED}") begin\r
+                        move (replaces("{RED}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 28\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{GREEN}") begin\r
+                        move (replaces("{GREEN}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 26\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{BLUE}") begin\r
+                        move (replaces("{BLUE}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 19\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{PURPLE}") begin\r
+                        move (replaces("{PURPLE}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 29\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{GREY}") begin\r
+                        move (replaces("{GREY}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 24\r
+                    end\r
+                    if (uppercase(l_sBuf) contains "{BLACK}") begin\r
+                        move (replaces("{BLACK}",l_sBuf,"")) to l_sBuf\r
+                        screenmode 16\r
+                    end\r
+\r
+                show (pad(mid(l_sBuf,80,l_iWidthAt),80))\r
+                screenmode 1\r
+            loop\r
+        close_input channel default_file_channel        \r
+    \r
+        move "lines " to l_sTmp\r
+        append l_sTmp (l_iLineAt+1) "-" (l_iLineAt+22) " of " (l_iTotalLines)\r
+        if (l_iTotalLines < (l_iLineAt+22)) begin\r
+            move "lines " to l_sTmp\r
+            append l_sTmp (l_iLineAt+1) "-" (l_iTotalLines) " of " (l_iTotalLines)\r
+        end\r
+        gotoxy 23 0\r
+        screenmode 112\r
+        show (center(l_sTmp,80)) \r
+        screenmode 1\r
+        \r
+        gotoxy 26 0\r
+        inkey l_k\r
+        if (key.up) begin\r
+            if (l_iLineAt <> 0) decrement l_iLineAt\r
+        end\r
+        if (key.down) begin\r
+            if ((l_iLineAt+22) < l_iTotalLines) increment l_iLineAt\r
+        end\r
+        if ((ascii(l_k)) = 34) begin\r
+            calc (l_iLineAt-22) to l_iLineAt\r
+            if (l_iLineAt < 0) move 0 to l_iLineAt\r
+        end\r
+        if ((ascii(l_k)) = 35) begin\r
+            calc (l_iLineAt+22) to l_iLineAt\r
+            if (l_iLineAt > (l_iTotalLines-22)) begin\r
+                move (l_iTotalLines-22) to l_iLineAt\r
+            end\r
+        end\r
+        if ((ascii(l_k)) = 44) begin\r
+            move 0 to l_iLineAt\r
+        end\r
+        if ((ascii(l_k)) = 45) begin\r
+            calc (l_iTotalLines-22) to l_iLineAt\r
+        end\r
+        if ((ascii(l_k)) = 4) begin\r
+            if (l_iWidthAt <> 1) decrement l_iWidthAt\r
+        end\r
+        if ((ascii(l_k)) = 5) begin\r
+            if ((l_iWidthAt+80) <= l_iTotalWidth) increment l_iWidthAt\r
+        end\r
+    loop\r
+end_function\r
+\r
+// Draw a large character in a dos window\r
+function draw_bigchar global string argv integer posx integer posy returns integer\r
+    local integer l_onCount l_i l_iChars\r
+    local string l_c\r
+    move 0 to l_onCount\r
+    move (uppercase(argv)) to argv\r
+    \r
+    send delete_data to (font_split(current_object))\r
+    send set_string to (font_split(current_object)) argv ","\r
+    get token_count of (font_split(current_object)) to l_iChars\r
+    \r
+    for l_i from 0 to (l_iChars+1)\r
+        get token_value of (font_split(current_object)) item l_i to l_c\r
+        if ((integer(l_c)) = 1) increment l_onCount\r
+        if (l_i < 8) begin\r
+            gotoxy posx (posy+l_i)\r
+            if ((integer(l_c)) = 0) show (character(32))\r
+            if ((integer(l_c)) = 1) show (character(219))\r
+        end\r
+        if ((l_i >= 8) and (l_i < 16)) begin\r
+            gotoxy (posx+1) (posy+l_i-8)\r
+            if ((integer(l_c)) = 0) show (character(32))\r
+            if ((integer(l_c)) = 1) show (character(219))\r
+        end\r
+        if ((l_i >= 16) and (l_i < 24)) begin\r
+            gotoxy (posx+2) (posy+l_i-16)\r
+            if ((integer(l_c)) = 0) show (character(32))\r
+            if ((integer(l_c)) = 1) show (character(219))\r
+        end\r
+        if ((l_i >= 24) and (l_i < 32)) begin\r
+            gotoxy (posx+3) (posy+l_i-24)\r
+            if ((integer(l_c)) = 0) show (character(32))\r
+            if ((integer(l_c)) = 1) show (character(219))\r
+        end\r
+        if ((l_i >= 32) and (l_i <= 40)) begin\r
+            gotoxy (posx+4) (posy+l_i-32)\r
+            if ((integer(l_c)) = 0) show (character(32))\r
+            if ((integer(l_c)) = 1) show (character(219))\r
+        end\r
+    loop\r
+    \r
+    function_return l_onCount\r
+end_function\r
+\r
+// Draw large text in a dos window\r
+function big_text global string argv integer posx integer posy returns integer\r
+    local integer l_iResult l_i\r
+    local string l_tmpStr\r
+\r
+    for l_i from 1 to  (length(argv))\r
+        move (mid(argv,1,l_i)) to l_tmpStr\r
+        get array_value of (font_array(current_object)) item (ascii(l_tmpStr)) to l_tmpStr\r
+        move (draw_bigchar(l_tmpStr,posx,(posy+((l_i-1)*9)))) to l_iResult\r
+    loop\r
+    function_return l_i\r
+end_function\r
diff --git a/src/df32/data.inc b/src/df32/data.inc
new file mode 100644 (file)
index 0000000..2bd8fa1
--- /dev/null
@@ -0,0 +1,2096 @@
+//-------------------------------------------------------------------------\r
+// data.inc\r
+//      This file contains some DataFlex 3.2 Console Mode classes\r
+//      to provide some useful data structures.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/data.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Classes\r
+//-------------------------------------------------------------------------\r
+\r
+// Linked list class - impliments a linked list type structure in an array, unlike\r
+// traditional linked lists the data is actually the prev/next links (array indexes)\r
+//\r
+// Prev and next addresses are stored as a string "prev,next" rather than using XORing;\r
+// this is so we can start traversal in either direction from a particular address\r
+// without having to also know the prev or next address.\r
+//\r
+// Get methods:\r
+//    probe_state                   - Returns a summary of the linked list state\r
+//    first_link                    - Returns the first link in the list\r
+//    last_link                     - Returns the last link in the list\r
+//    link_count                    - Returns the total number of links\r
+//    next_link <current_link>      - Returns the next link after the link id passed in\r
+//    prev_link <current_link>      - Returns the previous link after the link id passed in\r
+//\r
+// Set methods: (All of the following methods are intended to be private)\r
+//    next_link <current_link>      - Sets the next link after the link id passed in\r
+//    prev_link <current_link>      - Sets the previous link after the link id passed in\r
+//    seek_link                     - Seeks out the position in the list for a new link    \r
+//\r
+// Send message methods:\r
+//    insert_link                   - Insert a new item into the linked list\r
+//    remove_link                   - Remove an item from the linked list\r
+//\r
+//\r
+// Example usage:\r
+//    \r
+//    string buf\r
+//    integer max min count i\r
+//    \r
+//    object test is a linkedlist\r
+//    end_object\r
+//    \r
+//    // Create some links\r
+//    for i from 10 to 15\r
+//        send insert_link to test (i*100)\r
+//    loop\r
+//    for i from 1 to 5\r
+//        send insert_link to test (i*100)\r
+//    loop\r
+//    \r
+//    send insert_link to test 750\r
+//\r
+//    // Remove a link\r
+//    send remove_link to test 300\r
+//    \r
+//    // Access the list\r
+//    get probe_state of test to buf\r
+//    get first_link of test to min\r
+//    get last_link of test to max\r
+//    get link_count of test to count\r
+//    \r
+//    showln "There are " count " items in the linked list"\r
+//    showln buf\r
+//    \r
+//    show "Traverse forwards: "\r
+//    move min to i\r
+//    while (i <> -1) \r
+//        show i "->"   \r
+//        get next_link of test item i to i\r
+//    loop\r
+//    showln "END"\r
+//    \r
+//    show "Traverse backwards: "\r
+//    move max to i\r
+//    while (i <> -1) \r
+//        show i "->"   \r
+//        get prev_link of test item i to i\r
+//    loop\r
+//    showln "END"\r
+\r
+class linkedlist is an array\r
+    procedure construct_object integer argc\r
+        object mTokens is a StringTokenizer\r
+        end_object\r
+    \r
+        forward send construct_object\r
+        \r
+        property integer c_iMinAddr\r
+        property integer c_iMaxAddr\r
+        property integer c_iCount\r
+        property number c_nDist\r
+        \r
+        set c_iMinAddr to -1\r
+        set c_iMaxAddr to -1\r
+        set c_iCount to 0\r
+        set c_nDist to 1\r
+    end_procedure\r
+    \r
+    procedure delete_data\r
+        set c_iMinAddr to -1\r
+        set c_iMaxAddr to -1\r
+        set c_iCount to 0\r
+        set c_nDist to 1\r
+        forward send delete_data\r
+    end_procedure    \r
+    \r
+    function probe_state returns string\r
+        local integer l_iMinAddr l_iMaxAddr l_iCount \r
+        local number l_nDist\r
+        \r
+        get c_iMaxAddr to l_iMaxAddr\r
+        get c_iMinAddr to l_iMinAddr\r
+        get c_iCount to l_iCount\r
+        get c_nDist to l_nDist\r
+        \r
+        function_return ("Address range: "+string(l_iMinAddr)+"<->"+string(l_iMaxAddr)+" Items: "+string(l_iCount)+" Dist: "+string(l_nDist))\r
+    end_function\r
+    \r
+    function last_link returns integer\r
+        local integer l_iMaxAddr\r
+        \r
+        get c_iMaxAddr to l_iMaxAddr\r
+        \r
+        function_return l_iMaxAddr\r
+    end_function\r
+    \r
+    function first_link returns integer\r
+        local integer l_iMinAddr\r
+        \r
+        get c_iMinAddr to l_iMinAddr\r
+        \r
+        function_return l_iMinAddr\r
+    end_function    \r
+    \r
+    function link_count returns integer\r
+        local integer l_iCount\r
+        \r
+        get c_iCount to l_iCount\r
+        \r
+        function_return l_iCount\r
+    end_function      \r
+    \r
+    function next_link integer l_iAddr returns integer\r
+        local string l_sBuf\r
+        local integer l_iNext\r
+        \r
+        forward get string_value item l_iAddr to l_sBuf\r
+        if (l_sBuf = "") custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr\r
+        move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext\r
+        \r
+        function_return l_iNext\r
+    end_function\r
+    \r
+    function prev_link integer l_iAddr returns integer\r
+        local string l_sBuf\r
+        local integer l_iPrev\r
+        \r
+        forward get string_value item l_iAddr to l_sBuf\r
+        if (l_sBuf = "") custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr\r
+        move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev        \r
+        \r
+        function_return l_iPrev\r
+    end_function \r
+    \r
+    procedure set next_link integer l_iAddr integer l_iNext\r
+        local string l_sBuf\r
+        local integer l_iPrev\r
+        \r
+        forward get string_value item l_iAddr to l_sBuf\r
+        move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev\r
+        forward set array_value item l_iAddr to (string(l_iPrev)+","+string(l_iNext))\r
+        \r
+    end_procedure\r
+\r
+    procedure set prev_link integer l_iAddr integer l_iPrev\r
+        local string l_sBuf\r
+        local integer l_iNext\r
+        \r
+        forward get string_value item l_iAddr to l_sBuf\r
+        move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext\r
+        forward set array_value item l_iAddr to (string(l_iPrev)+","+string(l_iNext))\r
+        \r
+    end_procedure    \r
+    \r
+    function seek_link integer l_iAddr returns string\r
+        local integer l_iOn l_iNext l_iPrev l_iMinAddr l_iMaxAddr\r
+        local string l_sBuf\r
+        local number l_nDist\r
+        \r
+        get c_iMaxAddr to l_iMaxAddr\r
+        get c_iMinAddr to l_iMinAddr\r
+        get c_nDist to l_nDist\r
+\r
+\r
+        if (show_debug_lines) begin        \r
+            showln "DEBUG: Addr " l_iAddr\r
+            showln "DEBUG: Range " l_iMinAddr " <-> " l_iMaxAddr\r
+            showln "DEBUG: Dist " l_nDist\r
+        end\r
+        \r
+        move l_iMinAddr to l_iPrev\r
+        move l_iMaxAddr to l_iNext \r
+        \r
+        if (l_iAddr > l_iMaxAddr) move l_iMaxAddr to l_iOn\r
+        else move l_iMinAddr to l_iOn\r
+        \r
+        if (l_iOn > -1) begin\r
+            while (l_iOn < l_iAddr)\r
+                forward get string_value item l_iOn to l_sBuf\r
+            if (l_sBuf = "") break\r
+                else begin\r
+                    move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev\r
+                    move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext\r
+                end    \r
+                if ((l_iNext = -1) or (l_iNext > l_iAddr)) break             \r
+                move l_iNext to l_iOn\r
+            loop\r
+        end\r
+        \r
+        if (l_iPrev > l_iAddr) begin \r
+                move l_iPrev to l_iNext\r
+                move -1 to l_iOn\r
+            move -1 to l_iPrev\r
+        end            \r
+        \r
+        function_return (string(l_iPrev)+","+string(l_iOn)+","+string(l_iNext))\r
+    end_function\r
+    \r
+    procedure insert_link integer l_iAddr\r
+        local integer l_iMinAddr l_iMaxAddr l_iPrev l_iNext l_iOn l_iCount\r
+        local string l_sBuf\r
+        local number l_nDist\r
+        \r
+        if (l_iAddr < 0) custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr\r
+        else begin\r
+            forward get string_value item l_iAddr to l_sBuf\r
+            if (l_sBuf <> "") custom_error ERROR_CODE_ADDRESS_TAKEN$ ERROR_MSG_ADDRESS_TAKEN l_iAddr\r
+            else begin\r
+                get c_iMaxAddr to l_iMaxAddr\r
+            get c_iMinAddr to l_iMinAddr\r
+            get seek_link item l_iAddr to l_sBuf\r
+\r
+                send delete_data to (mTokens(current_object))\r
+                send set_string to (mTokens(current_object)) l_sBuf ","\r
+                get integer_value of (mTokens(current_object)) item 0 to l_iPrev\r
+                get integer_value of (mTokens(current_object)) item 1 to l_iOn\r
+                get integer_value of (mTokens(current_object)) item 2 to l_iNext\r
+                \r
+                if (show_debug_lines) begin\r
+                    showln "DEBUG: Insert address: " l_iAddr " Seek data '" l_sBuf "'"\r
+                end\r
+                \r
+                if (l_iOn <> -1) set next_link item l_iOn to l_iAddr  \r
+                forward set array_value item l_iAddr to (string(l_iOn)+","+string(l_iNext))\r
+                if (l_iNext <> -1) set prev_link item l_iNext to l_iAddr\r
+                \r
+                if (l_iAddr > l_iMaxAddr) begin \r
+                    move l_iAddr to l_iMaxAddr\r
+                    set c_iMaxAddr to l_iMaxAddr\r
+                end\r
+            if ((l_iAddr < l_iMinAddr) or (l_iMinAddr = -1)) begin\r
+                move l_iAddr to l_iMinAddr\r
+                set c_iMinAddr to l_iMinAddr\r
+            end\r
+            get c_iCount to l_iCount\r
+            get c_nDist to l_nDist\r
+            increment l_iCount\r
+            set c_iCount to l_iCount\r
+            set c_nDist to (number(l_iCount)/(l_iMaxAddr-l_iMinAddr))\r
+            end\r
+        end\r
+    end_procedure\r
+    \r
+    procedure remove_link integer l_iAddr\r
+        local integer l_iMinAddr l_iMaxAddr l_iPrev l_iNext l_iOn l_iCount\r
+        local string l_sBuf\r
+        local number l_nDist\r
+        \r
+        if (l_iAddr < 0) custom_error ERROR_CODE_INVALID_ADDRESS$ ERROR_MSG_INVALID_ADDRESS l_iAddr\r
+        else begin\r
+            get c_iMaxAddr to l_iMaxAddr\r
+            get c_iMinAddr to l_iMinAddr\r
+            forward get string_value item l_iAddr to l_sBuf\r
+            \r
+            move (integer(left(l_sBuf,pos(",",l_sBuf)-1))) to l_iPrev\r
+            move (integer(right(l_sBuf,(length(l_sBuf)-pos(",",l_sBuf))))) to l_iNext\r
+            \r
+            if (show_debug_lines) begin\r
+                showln "DEBUG: Remove address: " l_iAddr " Link data '" l_sBuf "'"\r
+            end\r
+            \r
+            if (l_iPrev <> -1) set next_link item l_iPrev to l_iNext\r
+            if (l_iNext <> -1) set prev_link item l_iNext to l_iPrev\r
+            forward set array_value item l_iAddr to ""\r
+            \r
+            if (l_iMaxAddr = l_iAddr) set c_iMaxAddr to l_iPrev            \r
+            if (l_iMinAddr = l_iAddr) set c_iMinAddr to l_iNext            \r
+            \r
+            get c_iCount to l_iCount\r
+            get c_nDist to l_nDist\r
+            decrement l_iCount\r
+            set c_iCount to l_iCount\r
+            set c_nDist to (number(l_iCount)/(l_iMaxAddr-l_iMinAddr))                        \r
+        end        \r
+    end_procedure\r
+\r
+end_class\r
+\r
+// Hashtable class - unlike other similar "hash" data structures which usually\r
+// store key/value pairs; the hashtable class was only initially intended to \r
+// store a key and return a hash index.  Typical use would usually have been \r
+// to then store the value in an array at the hash index.  (See the "hash" class\r
+// below for a key/value orientated class)\r
+// It is however possible to use insert_at_hash and find_at_hash to store a different\r
+// value at a particular key hash, this is however an afterthought and colisions are \r
+// possible.\r
+//\r
+// Send message methods:\r
+//    delete_data       - Clear the hashtable\r
+//    hash_algorithm    - Set the hash algorithm, any of ("hash_for_df_arrays", \r
+//                        "hash_reduced_djb2", "hash_reduced_lazy", "hash_reduced_sdbm")\r
+//                        with "hash_for_df_arrays" being the default.\r
+//    remove_hash       - Removes an item from the hashtable.\r
+//\r
+// Set methods:\r
+//    item_ptr          - Set the index of the current item_ptr (next_hash will return the next item from this)\r
+//\r
+// Get methods:\r
+//    item_count\r
+//    insert_hash       - Insert a value (where the key is equal to the value) and return hash index\r
+//    insert_at_hash    - Insert a value at the hash index of a key and return hash index\r
+//    find_hash         - Check if a value is stored in the hash (where the key is equal to the value) and return it's hash index\r
+//    find_at_hash      - Check if a value is stored in the hash at the hash index of a key and return it's hash index\r
+//    value_at_index    - Return the value stored at a particular hash index\r
+//    string_at_index   - Same as above, but specifically retun in string context\r
+//    next_hash         - Get the next value stored in the hash\r
+//    item_ptr          - Get the index of the last value returned by next_hash\r
+//\r
+// Example usage:\r
+//\r
+//    object myHashtable is a hashTable\r
+//    end_object\r
+//\r
+//    integer i ix\r
+//    string k\r
+//\r
+//    clearscreen\r
+//    get insert_hash of (myHashtable(current_object)) item "ABC" to i\r
+//    get insert_hash of (myHashtable(current_object)) item "HELLO" to ix\r
+//    get insert_hash of (myHashtable(current_object)) item "ZZZ" to i\r
+//    send remove_hash to (myHashtable(current_object)) ix\r
+//    get item_count of (myHashtable(current_object)) to i  \r
+//\r
+//    get find_hash of (myHashtable(current_object)) item "HELLO" to i\r
+//    showln i\r
+//\r
+//    set item_ptr of (myHashTable(current_object)) to 0\r
+//    move 0 to i\r
+//    while (i  <> -1)\r
+//        get next_hash of (myHashtable(current_object)) to k\r
+//        get item_ptr of (myHashtable(current_object)) to i  \r
+//\r
+//        showln "*** " i " " k\r
+//        inkey k\r
+//    loop\r
+//\r
+class hashtable is an array\r
+    procedure construct_object integer argc\r
+        forward send construct_object\r
+        property integer c_iMaxHash public argc\r
+        property integer c_iMinHash\r
+        property integer c_iItems\r
+        property integer c_iItemP\r
+        property string c_sHashAlgorithm\r
+        set c_sHashAlgorithm to "hash_for_df_arrays"\r
+        set c_iMinHash to 99999999\r
+    end_procedure\r
+        \r
+    procedure delete_data\r
+        set c_iMinHash to 0\r
+        set c_iMaxHash to 0\r
+        set c_iItems to 0\r
+        set c_iItemP to 0\r
+        forward send delete_data\r
+    end_procedure\r
+        \r
+    procedure hash_algorithm string l_sType\r
+        local integer l_iItems\r
+        \r
+        get c_iItems to l_iItems\r
+        \r
+        // Allow algorithm change only when empty.\r
+        if (l_iItems = 0) begin\r
+            if (trim(lowercase(l_sType)) = "hash_for_df_arrays") set c_sHashAlgorithm to "hash_for_df_arrays"\r
+            if (trim(lowercase(l_sType)) = "hash_reduced_djb2") set c_sHashAlgorithm to "hash_reduced_djb2"\r
+            if (trim(lowercase(l_sType)) = "hash_reduced_sdbm") set c_sHashAlgorithm to "hash_reduced_sdbm"\r
+            if (trim(lowercase(l_sType)) = "hash_reduced_lazy") set c_sHashAlgorithm to "hash_reduced_lazy"\r
+        end\r
+    end_procedure\r
+        \r
+    procedure set item_ptr integer l_iItemP\r
+        set c_iItemP to l_iItemp\r
+    end_procedure\r
+        \r
+    function item_ptr returns integer\r
+        local integer l_iItemP\r
+        get c_iItemP to l_iItemP\r
+        function_return l_iItemP\r
+    end_function\r
+        \r
+    procedure remove_hash integer l_iHash\r
+        local string l_sNext\r
+        local integer l_iItems\r
+        \r
+        get c_iItems to l_iItems\r
+        if (l_iItems > 0) begin\r
+            forward get array_value item (l_iHash+1) to l_sNext\r
+            if (trim(l_sNext) <> "") forward set array_value item l_iHash to "<!!#ITEM REMOVED#!!>"\r
+            if (trim(l_sNext) = "") forward set array_value item l_iHash to ""\r
+            set c_iItems to (l_iItems-1)\r
+        end\r
+    end_procedure\r
+        \r
+    function item_count returns integer\r
+            local integer l_iItems\r
+            get c_iItems to l_iItems\r
+            function_return l_iItems\r
+    end_procedure\r
+        \r
+    function write_hash string l_sHash string l_sValue returns integer\r
+        local integer l_iHash l_iMinHash l_iMaxHash l_iItems l_iReuse\r
+        local string l_sTmp l_sHashAlgorithm l_sStorage\r
+\r
+        if (l_sValue = "") begin\r
+            move l_sHash to l_sStorage\r
+        end\r
+        else begin\r
+            move l_sValue to l_sStorage\r
+        end\r
+\r
+        // Get our object properties\r
+        get c_iMaxHash to l_iMaxHash\r
+        get c_iMinHash to l_iMinHash\r
+        get c_iItems to l_iItems\r
+        get c_sHashAlgorithm to l_sHashAlgorithm\r
+        \r
+        // Generate an initial hash\r
+        move 0 to l_iHash\r
+        \r
+        case begin\r
+            case (l_sHashAlgorithm = "hash_reduced_djb2") move (reduce_hash(hash_djb2(l_sHash))) to l_iHash\r
+            case break\r
+            case (l_sHashAlgorithm = "hash_reduced_sdbm") move (reduce_hash(hash_sdbm(l_sHash))) to l_iHash\r
+            case break\r
+            case (l_sHashAlgorithm = "hash_reduced_lazy") move (reduce_hash(hash_lazy(l_sHash))) to l_iHash\r
+            case break\r
+            case else move (hash_for_df_arrays(l_sHash)) to l_iHash\r
+            case break\r
+        case end\r
+        \r
+        // Then we check in the array to see if out hash is available or equal\r
+        // if not we bucket the value by moveing along into the next available slot\r
+        move 0 to l_iReuse\r
+        next_bucket01:\r
+        forward get string_value item l_iHash to l_sTmp\r
+        if ((l_sTmp <> "") and (l_sTmp <> l_sStorage)) begin\r
+            // If we come across a removed item we may want to reuse the hash space\r
+            if ((l_sTmp = "<!!#ITEM REMOVED#!!>") and (l_iReuse = 0)) move l_iHash to l_iReuse \r
+            calc (l_iHash+1) to l_iHash\r
+            goto next_bucket01\r
+        end\r
+            \r
+        // If this is a new object and we have a slot to reuse then do so here\r
+        if ((l_iReuse <> 0) and (l_sTmp = "")) move l_iReuse to l_iHash \r
+        if (l_iHash > l_iMaxHash) move l_iHash to l_iMaxHash\r
+        if (l_iHash < l_iMinHash) move l_iHash to l_iMinHash\r
+        forward set array_value item l_iHash to l_sStorage\r
+        \r
+        set c_iMaxHash to l_iMaxHash\r
+        set c_iMinHash to l_iMinHash\r
+        set c_iItems to (l_iItems+1)\r
+        \r
+        function_return l_iHash\r
+    end_function\r
+\r
+    function insert_hash string l_sHash returns integer\r
+        local integer l_iHash\r
+        get write_hash item l_sHash item "" to l_iHash\r
+        function_return l_iHash\r
+    end_procedure\r
+        \r
+    function insert_at_hash string l_sHash string l_sValue returns integer\r
+        local integer l_iHash\r
+        get write_hash item l_sHash item l_sValue to l_iHash\r
+        function_return l_iHash\r
+    end_procedure\r
+        \r
+    function read_hash string l_sHash string l_sValue returns integer\r
+        local integer l_iHash l_iMinHash l_iMaxHash l_iItems\r
+        local string l_sTmp l_sHashAlgorithm l_sStorage\r
+\r
+        if (l_sValue = "") begin\r
+            move l_sHash to l_sStorage\r
+        end\r
+        else begin\r
+            move l_sValue to l_sStorage\r
+        end\r
+\r
+        // Get our object properties\r
+        get c_iMaxHash to l_iMaxHash\r
+        get c_iMinHash to l_iMinHash\r
+        get c_iItems to l_iItems\r
+        get c_sHashAlgorithm to l_sHashAlgorithm\r
+        \r
+        // Generate an initial hash\r
+        move 0 to l_iHash\r
+        \r
+        case begin\r
+            case (l_sHashAlgorithm = "hash_reduced_djb2") move (reduce_hash(hash_djb2(l_sHash))) to l_iHash\r
+            case break\r
+            case (l_sHashAlgorithm = "hash_reduced_sdbm") move (reduce_hash(hash_sdbm(l_sHash))) to l_iHash\r
+            case break\r
+            case (l_sHashAlgorithm = "hash_reduced_lazy") move (reduce_hash(hash_lazy(l_sHash))) to l_iHash\r
+            case break\r
+            case else move (hash_for_df_arrays(l_sHash)) to l_iHash\r
+            case break\r
+        case end\r
+\r
+        // Then we check in the array to see if our hash is available or equal\r
+        // if not we bucket the value by moveing along into the next available slot\r
+        next_bucket02:\r
+        forward get string_value item l_iHash to l_sTmp\r
+        \r
+        if ((l_sTmp <> "") and (l_sTmp <> l_sStorage)) begin\r
+                calc (l_iHash+1) to l_iHash\r
+                goto next_bucket02\r
+        end\r
+        if (l_sTmp <> l_sStorage) move -1 to l_iHash\r
+        \r
+        function_return l_iHash\r
+    end_function\r
+    \r
+    function find_hash string l_sHash returns integer\r
+        local integer l_iHash\r
+        get read_hash item l_sHash item "" to l_iHash\r
+        function_return l_iHash\r
+    end_function\r
+    \r
+    function find_at_hash string l_sHash string l_sValue returns integer\r
+        local integer l_iHash\r
+        get read_hash item l_sHash item l_sValue to l_iHash\r
+        function_return l_iHash\r
+    end_function\r
+\r
+    function value_at_index integer l_iHash returns string\r
+        local string l_sBuf\r
+\r
+        forward get array_value item l_iHash to l_sBuf\r
+        \r
+        function_return l_sBuf\r
+    end_function\r
+    \r
+    function string_at_index integer l_iHash returns string\r
+        local string l_sBuf\r
+\r
+        forward get string_value item l_iHash to l_sBuf\r
+        \r
+        function_return l_sBuf\r
+    end_function    \r
+    \r
+    function next_hash returns string\r
+        local string l_sBuf\r
+        local integer l_iItemP l_iMaxHash l_iMinHash\r
+        \r
+        get c_iItemP to l_iItemP\r
+        get c_iMaxHash to l_iMaxHash\r
+        get c_iMinHash to l_iMinHash\r
+        \r
+        if (l_iMinHash > l_iItemP) move (l_iMinHash-1) to l_iItemP\r
+        \r
+        move "" to l_sBuf\r
+        while ((l_sBuf = "") and (l_iItemP <= l_iMaxHash))\r
+            increment l_iItemP \r
+            forward get array_value item l_iItemP to l_sBuf\r
+            if (trim(l_sBuf) = "<!!#ITEM REMOVED#!!>") move "" to l_sBuf            \r
+        loop\r
+        \r
+        if (l_iItemP > l_iMaxHash) move -1 to l_iItemP\r
+        set c_iItemP to l_iItemP\r
+    \r
+        function_return l_sBuf\r
+    end_function \r
+    \r
+end_class\r
+\r
+// Hash class - more akin to similar "hash" data structures in other languages\r
+// which stores key/value pairs.\r
+// This is a quick 5 minute implementation, it depends on the hashtable object \r
+// above for it's hashing.\r
+//\r
+// Send message methods:\r
+//\r
+//    truncate          - Clear the hash\r
+//    remove_key        - Removes a key/value pair from the hash\r
+//\r
+// Set methods:\r
+//    value_at_key      - Gets the value stored for a particular key\r
+//\r
+// Get methods:\r
+//    insert_key        - Inserts a key/value pair into the hash\r
+//    value_at_key      - Retrieves the value stored for a particular key\r
+//    item_count        - Retrieves the count of items in the hash\r
+//\r
+//    Example usage:\r
+//    \r
+//    \r
+//    string key iv buf\r
+//    integer i\r
+//    \r
+//    object test is a hash\r
+//    end_object\r
+//    \r
+//    send insert_key to test "INDEX 1" "VALUE 1"\r
+//    send insert_key to test "INDEX 2" "VALUE 2"\r
+//    send insert_key to test "INDEX 3" "VALUE 3"\r
+//    \r
+//    get first_key of test to key\r
+//    showln "KEY " key\r
+//    get value_at_key of test item key to buf\r
+//    showln "VALUE " buf\r
+//    \r
+//    while (key <> "") \r
+//        get next_key of test key to key\r
+//        if (key <> "") begin\r
+//            showln "KEY " key\r
+//            get value_at_key of test item key to buf\r
+//            showln "VALUE " buf\r
+//        end\r
+//    loop\r
+//    \r
+//    set value_at_key of test item "INDEX 2" item "VALUE TWO"\r
+//    showln "SET VALUE AT 'INDEX 2'"\r
+//    \r
+//    get value_at_key of test item "INDEX 1" to buf\r
+//    showln "LOOKUP 'INDEX 1' = " buf\r
+//    get value_at_key of test item "INDEX 2" to buf\r
+//    showln "LOOKUP 'INDEX 2' = " buf\r
+//    \r
+//    get item_count of test to i\r
+//    showln "ITEM COUNT " i\r
+//    \r
+//    send remove_key to test "INDEX 3"\r
+//    showln "REMOVE AT KEY: 'INDEX 3'"\r
+//    \r
+//    get item_count of test to i\r
+//    showln "ITEM COUNT " i\r
+//    \r
+//    get value_at_key of test item "INDEX 3" to buf\r
+//    showln "LOOKUP 'INDEX 3' =" buf\r
+//    \r
+//    send truncate to test\r
+//    showln "TRUNCATED"\r
+//    \r
+//    get value_at_key of test item "INDEX 1" to buf\r
+//    showln "LOOKUP 'INDEX 1' = " buf\r
+//    \r
+//    get item_count of test to i\r
+//    showln "EMPTY COUNT " i\r
+//\r
+class hash is an array\r
+    procedure construct_object integer argc\r
+        object keystore is a hashtable\r
+        end_object\r
+        \r
+        object linkstore is a linkedlist\r
+        end_object\r
+        \r
+        forward send construct_object\r
+    end_procedure\r
+\r
+    procedure truncate\r
+        send delete_data to (keystore(current_object))\r
+        send delete_data to (linkstore(current_object))\r
+        \r
+        forward send delete_data\r
+    end_procedure    \r
+    \r
+    procedure remove_key string l_sKey\r
+        local integer l_iIndex\r
+        get find_hash of (keystore(current_object)) item l_sKey to l_iIndex\r
+        if (l_iIndex <> -1) begin\r
+            send remove_hash to (keystore(current_object)) l_iIndex\r
+            send remove_link to (linkstore(current_object)) l_iIndex\r
+            forward set array_value item l_iIndex to ""\r
+        end\r
+    end_procedure\r
+    \r
+    procedure set value_at_key string l_sKey string l_sValue\r
+        local integer l_iIndex\r
+        \r
+        get find_hash of (keystore(current_object)) item l_sKey to l_iIndex\r
+        forward set array_value item l_iIndex to l_sValue\r
+        \r
+    end_procedure\r
+    \r
+    procedure insert_key string l_sKey string l_sValue\r
+        local integer l_iIndex\r
+        \r
+        get insert_hash of (keystore(current_object)) item l_sKey to l_iIndex\r
+        send insert_link to (linkstore(current_object)) l_iIndex\r
+        forward set array_value item l_iIndex to l_sValue\r
+        \r
+    end_procedure\r
+    \r
+    function value_at_key string l_sKey returns string\r
+        local integer l_iIndex\r
+        local string l_sValue\r
+        \r
+        get find_hash of (keystore(current_object)) item l_sKey to l_iIndex\r
+        forward get string_value item l_iIndex to l_sValue\r
+        \r
+        function_return l_sValue\r
+    end_function\r
+    \r
+    function first_key returns string\r
+        local integer l_iIndex\r
+        local string l_sKey\r
+        \r
+        get first_link of (linkstore(current_object)) to l_iIndex\r
+        get string_at_index of (keystore(current_object)) item l_iIndex to l_sKey\r
+\r
+        function_return l_sKey\r
+    end_function    \r
+    \r
+    function next_key string l_sKey returns string\r
+        local integer l_iIndex\r
+        \r
+        get find_hash of (keystore(current_object)) item l_sKey to l_iIndex\r
+        get next_link of (linkstore(current_object)) item l_iIndex to l_iIndex\r
+        get string_at_index of (keystore(current_object)) item l_iIndex to l_sKey\r
+\r
+        function_return l_sKey\r
+    end_function\r
+    \r
+    function item_count returns integer\r
+        local integer l_iResult\r
+        get item_count of (keystore(current_object)) to l_iResult\r
+        \r
+        function_return l_iResult\r
+    end_function\r
+end_class\r
+\r
+// Matrix class - Provides an indexed two-dimensional array / matrix class\r
+//\r
+// This class is sensitive to ascii char 1, which is used for delimiting values \r
+// within the second dimension.  The implimentation is rather unrefined and \r
+// stores delimited values within an array, thus the wider the matrix the \r
+// slower any adding removing or sorting will be. \r
+//\r
+// This is designed purely as a convenience to provide something matrix like within \r
+// the limitations of DataFlex 3.2 Console Mode; be sure to keep this in mind before \r
+// using.\r
+//\r
+// To allow quick lookup of linked data, a hash index may be created on one column \r
+// of a matrix at a time.\r
+// A hash index may be added both before and after populating the matrix with your \r
+// data.\r
+//\r
+// As with a hash table the hasing algorithm may be set for the matrix, but to take\r
+// affect this must be called before the hash_on_column message. (see hash.inc \r
+// function for available algorithms)\r
+//        \r
+// The hash_is_unique and remove_hash_is_unique messages allow enforcement of unique\r
+// values in the hashed column.  If the hash_is_unique message is sent after the \r
+// creation of a hash index on a matrix already populated with data the constraint will \r
+// only apply to new data.\r
+//    \r
+// The hash may also be removed from the column (freeing up any memory used, which can\r
+// be fairly large) at any time, this allows for removing the hash from one column and \r
+// re-assigning it to another or changing hash algorithm on the same data.\r
+//  \r
+// Lookups on the hash index are performed with the matrix_index_from_value, matrix_index_count_from_value\r
+//\r
+// Send message methods:\r
+//    delete_data                   - Clear the matrix\r
+//    matrix_sort                   - Y pos to sort on\r
+//    matrix_delete                 - X and Y pos to delete \r
+//    delete_item                   - X position to delete (this reshuffles the matrix; avoid using)\r
+//    hash_on_column_algorithm      - Hash algorithm to use\r
+//    hash_on_column                - Y pos of column to hash\r
+//    remove_hash_on_column         - Remove the hash from the column\r
+//    hash_is_unique                - Add a unique constraint on the hash\r
+//    remove_hash_is_unique         - Remove a unique constraint from the hash\r
+//    matrix_index_lookup_clear     - Clear the lookup buffer\r
+//\r
+// Set methods:\r
+//    matrix_value                  - Set a value at X, Y\r
+//    matrix_string    \r
+//\r
+// Get methods:\r
+//    matrix_value                  - Get a value at X, Y\r
+//    matrix_string                 - Get an string value at X, Y\r
+//    matrix_integer                - Get an integer value at X, Y\r
+//    matrix_numeric                - Get an numeric value at X, Y\r
+//    matrix_real                   - Get an real value at X, Y\r
+//    matrix_hash_from_value        - Get the hash index value used for an indexed column value\r
+//    matrix_indextable_from_value  - Get list of matrix x pos indexes for a particular hashed value\r
+//    matrix_index_lookup_clear     - Clear the buffer for an indexed lookup\r
+//    matrix_index_count_from_value - Get a count of rows with a particular value\r
+//    matrix_index_from_value       - Get the next X pos (row) with indexed value. Returns -1 when nothing left to find.\r
+//    \r
+// Example usage:\r
+//\r
+//\r
+//    object test is a matrix\r
+//    end_object\r
+//\r
+//    set matrix_value of (test(current_object)) item 0 item 1 to "1"    - x then y pos to Value\r
+//    get matrix_value of (test(current_object)) item 0 item 1 to tmpStr - x then y pos to Value\r
+//    send matrix_sort to (test(current_object)) 1               - x then y pos to sort by\r
+//    send matrix_delete to (test(current_object)) 1 1           - x then y pos to delete \r
+//    send matrix_delete_row to (test(current_object)) 1             - x essentially blanks record out, no reshuffle\r
+//    send delete_item to (test1(current_object)) 1              - x pos (not v efficient), reshuffles\r
+//\r
+// Hash indexed columns usage:\r
+//\r
+//    send hash_on_column_algorithm to (test(current_object)) "hash_reduced_lazy"\r
+//    send hash_on_column to (test(current_object)) 0\r
+//    send remove_hash_on_column to (test(current_object)) \r
+//    send hash_is_unique to (test(current_object)) \r
+//    \r
+//    send matrix_index_lookup_clear to (test(current_object)) \r
+//    get matrix_index_count_from_value of (test(current_object)) item "1" to count\r
+//    get matrix_index_from_value of (test(current_object)) item "1" to x_pos   \r
+//    get matrix_indextable_from_value of (test(current_object)) item "1" to tmpStr \r
+//    get matrix_hash_from_value of (test(current_object)) item "1" to tmpInt   \r
+\r
+class matrix is an array\r
+    procedure construct_object integer argc\r
+        object mTokens is a StringTokenizer\r
+        end_object\r
+    \r
+        forward send construct_object\r
+        property integer c_iWidth public argc\r
+        property integer c_iHashOn\r
+        property integer c_iLastIndexTableHash\r
+        property integer c_iLastIndexTablePos\r
+        property integer c_iEnforceUnique\r
+        property string c_sHashAlgorithm\r
+        \r
+        set c_sHashAlgorithm to ""\r
+        set c_iHashOn to -1\r
+        set c_iLastIndexTableHash to -1\r
+        set c_iLastIndexTablePos to -1\r
+        set c_iEnforceUnique to 0\r
+    end_procedure\r
+    \r
+    procedure hash_on_column_algorithm string hashalg\r
+        if ((hashalg = "hash_reduced_djb2") or (hashalg = "hash_reduced_sdbm") or (hashalg = "hash_reduced_lazy") or (hashalg = "hash_for_df_arrays") or (hashalg = "")) begin\r
+            set c_sHashAlgorithm to hashalg\r
+        end     \r
+    end_procedure\r
+    \r
+    procedure hash_is_unique\r
+        set c_iEnforceUnique to 1\r
+    end_procedure   \r
+    \r
+    procedure remove_hash_is_unique\r
+        set c_iEnforceUnique to 0\r
+    end_procedure   \r
+    \r
+    procedure hash_on_column integer l_iColumn\r
+        local integer l_iMax l_iHashOn l_i l_iHash l_iEnforceUnique l_iHashError\r
+        local string l_sBuf l_sTmp l_sHashAlgorithm \r
+        \r
+        forward get item_count to l_iMax\r
+        get c_iHashOn to l_iHashOn\r
+        \r
+        // Allow adding hash only when no hash already set\r
+        if ((l_iHashOn = -1) and (l_iColumn >= 0)) begin\r
+                            \r
+            object mHash_array is an array\r
+            end_object              \r
+                \r
+            object mHash_table is a hashTable\r
+            end_object\r
+                \r
+            get c_sHashAlgorithm to l_sHashAlgorithm\r
+            get c_iEnforceUnique to l_iEnforceUnique\r
+            \r
+            if (l_sHashAlgorithm <> "") begin\r
+                send hash_algorithm to (mHash_table(current_object)) l_sHashAlgorithm\r
+            end\r
+            \r
+            if (l_iMax <> 0) begin\r
+                // Hash the current matrix if not empty\r
+                move (l_iMax-1) to l_iMax       \r
+                \r
+                for l_i from 0 to l_iMax\r
+                    forward get array_value item l_i to l_sBuf\r
+                \r
+                    send delete_data to (mTokens(current_object))\r
+                    send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+                    get token_value of (mTokens(current_object)) item l_iColumn to l_sTmp                                       \r
+                    get insert_hash of (mHash_table(current_object)) item l_sTmp to l_iHash\r
+                    get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                        \r
+                    if ((l_iEnforceUnique = 1) and (length(replace("|",l_sTmp,"")) <> 0)) begin\r
+                        custom_error ERROR_CODE_DUPLICATE_HASH_KEY$ ERROR_MSG_DUPLICATE_HASH_KEY ERROR_DETAIL_DUPLICATE_HASH_KEY l_iColumn\r
+                        move 1 to l_iHashError\r
+                        break\r
+                    end\r
+                    else if not (l_sTmp contains ("|"+string(l_i)+"|")) begin\r
+                        if (length(l_sTmp) = 0) move "|" to l_sTmp\r
+                        append l_sTmp (string(l_i)+"|")\r
+                        set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                    end\r
+                loop\r
+            end\r
+                \r
+            if (l_iHashError = 0) begin\r
+                set c_iHashOn to l_iColumn\r
+            end\r
+            else begin\r
+                send destroy_object to (mHash_array(current_object))\r
+                send destroy_object to (mHash_table(current_object))                    \r
+            end\r
+        end\r
+    end_procedure\r
+        \r
+    procedure remove_hash_on_column\r
+        local integer l_iHashOn\r
+        \r
+        get c_iHashOn to l_iHashOn\r
+        \r
+        if (l_iHashOn <> -1) begin          \r
+            set c_iHashOn to -1\r
+            send destroy_object to (mHash_array(current_object))\r
+            send destroy_object to (mHash_table(current_object))\r
+        end\r
+    end_procedure\r
+        \r
+    procedure set matrix_value integer itemx integer itemy string val\r
+        local string l_sBuf l_sTmp l_sOldVal \r
+        local integer l_i l_iWidth l_iHashOn l_iHash l_iEnforceUnique l_iHashError\r
+\r
+        move 0 to l_iHashError\r
+        get c_iWidth to l_iWidth\r
+        get c_iHashOn to l_iHashOn\r
+        \r
+        forward get array_value item itemx to l_sBuf\r
+                        \r
+        if (itemy > l_iWidth) begin\r
+                set c_iWidth to itemy\r
+                move itemy to l_iWidth\r
+        end\r
+\r
+        // Delimiter is ascii char 1 (start of heading/console interrupt)\r
+        // so any values containing ascii 1 will, of course break the matrix\r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        \r
+        if (l_iHashOn = itemy) begin\r
+            get token_value of (mTokens(current_object)) item itemy to l_sOldVal\r
+        end\r
+        if (val = "") set token_value of (mTokens(current_object)) item itemy to (character(3))\r
+        else set token_value of (mTokens(current_object)) item itemy to (replaces(character(1),(replaces(character(3),val,"")),""))\r
+    \r
+        move "" to l_sBuf\r
+        for l_i from 0 to l_iWidth                        \r
+            get token_value of (mTokens(current_object)) item l_i to l_sTmp                        \r
+            if (length(l_sTmp) = 0) move (character(3)) to l_sTmp        \r
+            if (length(l_sBuf) <> 0) append l_sBuf (character(1))\r
+            append l_sBuf l_sTmp\r
+        loop\r
+                \r
+        move (replaces(character(3),l_sBuf,"")) to l_sBuf\r
+                    \r
+        // Insert/update in the value to the hash\r
+        if ((l_iHashOn = itemy) and (l_sOldVal <> val)) begin       \r
+            get c_iEnforceUnique to l_iEnforceUnique\r
+            get insert_hash of (mHash_table(current_object)) item val to l_iHash\r
+            get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+            \r
+            if ((l_iEnforceUnique = 1) and (length(replace("|",l_sTmp,"")) <> 0)) begin\r
+                custom_error ERROR_CODE_DUPLICATE_HASH_KEY$ ERROR_MSG_DUPLICATE_HASH_KEY ERROR_DETAIL_DUPLICATE_HASH_KEY itemy\r
+                move 1 to l_iHashError\r
+            end\r
+            else if not (l_sTmp contains ("|"+string(itemx)+"|")) begin\r
+                if (length(l_sTmp) = 0) move "|" to l_sTmp\r
+                append l_sTmp (string(itemx)+"|")\r
+                set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+            end\r
\r
+            // Remove old hash (if any) when insert succeeds\r
+            if (l_iHashError = 0) begin\r
+                get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash\r
+                if (l_iHash <> 0) begin\r
+                    get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp                \r
+                    if (l_sTmp contains ("|"+string(itemx)+"|")) begin\r
+                        move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp\r
+                        if (l_sTmp = "") begin\r
+                            send remove_hash to (mHash_table(current_object)) l_iHash\r
+                        end\r
+                        else begin\r
+                            if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp\r
+                            else append l_sTmp "|"\r
+                        end\r
+                        set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                    end\r
+                end\r
+            end\r
+        end\r
+                \r
+        if (l_iHashError = 0) begin\r
+            forward set array_value item itemx to l_sBuf\r
+        end\r
+    end_procedure\r
+    \r
+    function matrix_string integer itemx integer itemy returns string\r
+        local string l_sBuf l_sTmp\r
+\r
+        forward get array_value item itemx to l_sBuf\r
+        \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        get token_value of (mTokens(current_object)) item itemy to l_sTmp\r
+        \r
+        function_return l_sTmp\r
+    end_function        \r
+    \r
+    function matrix_value integer itemx integer itemy returns string\r
+        local string l_sBuf l_sTmp\r
+\r
+        forward get array_value item itemx to l_sBuf\r
+        \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        get token_value of (mTokens(current_object)) item itemy to l_sTmp\r
+        \r
+        function_return l_sTmp\r
+    end_function        \r
+    \r
+    function matrix_integer integer itemx integer itemy returns integer\r
+        local string l_sBuf\r
+        local integer l_iTmp\r
+\r
+        forward get array_value item itemx to l_sBuf\r
+        \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        get token_value of (mTokens(current_object)) item itemy to l_iTmp\r
+        \r
+        function_return l_iTmp\r
+    end_function\r
+    \r
+    function matrix_number integer itemx integer itemy returns number\r
+        local string l_sBuf\r
+        local number l_nTmp\r
+        \r
+        forward get array_value item itemx to l_sBuf\r
+        \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        get token_value of (mTokens(current_object)) item itemy to l_nTmp\r
+        \r
+        function_return l_nTmp\r
+    end_function\r
+    \r
+    function matrix_real integer itemx integer itemy returns real\r
+        local string l_sBuf\r
+        local real l_rTmp\r
+        \r
+        forward get array_value item itemx to l_sBuf\r
+        \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        get token_value of (mTokens(current_object)) item itemy to l_rTmp\r
+        \r
+        function_return l_rTmp\r
+    end_function\r
+    \r
+    function matrix_hash_from_value string val returns integer\r
+        local integer l_iHash l_iHashOn\r
+        \r
+        get c_iHashOn to l_iHashOn\r
+                \r
+        if (l_iHashOn <> -1) begin\r
+            get find_hash of (mHash_table(current_object)) item val to l_iHash\r
+        end\r
+\r
+        function_return l_iHash\r
+    end_function\r
+    \r
+    function matrix_indextable_from_value string val returns string\r
+        local integer l_iHashOn l_iHash\r
+        local string l_sIndexTable\r
+\r
+        get c_iHashOn to l_iHashOn\r
+                \r
+        if (l_iHashOn <> -1) begin\r
+            get find_hash of (mHash_table(current_object)) item val to l_iHash\r
+            get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable\r
+        end\r
+\r
+        function_return l_sIndexTable\r
+    end_function\r
+        \r
+    procedure matrix_index_lookup_clear \r
+        local integer l_iHashOn\r
+        \r
+        get c_iHashOn to l_iHashOn\r
+    \r
+        if (l_iHashOn <> -1) begin\r
+            set c_iLastIndexTableHash to -1\r
+            set c_iLastIndexTablePos to -1\r
+        end\r
+    end_procedure\r
+        \r
+    function matrix_index_from_value string val returns integer\r
+        local integer l_iHashOn l_iHash l_iLastIndexTableHash l_iLastIndexTablePos l_iIndex l_iIndexValues\r
+        local string l_sIndexTable\r
+\r
+        get c_iHashOn to l_iHashOn\r
+        move -1 to l_iIndex\r
+            \r
+        if (l_iHashOn <> -1) begin\r
+            get find_hash of (mHash_table(current_object)) item val to l_iHash\r
+            get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable\r
+\r
+            get c_iLastIndexTableHash to l_iLastIndexTableHash          \r
+            \r
+            if (l_iHash = l_iLastIndexTableHash) begin\r
+                get c_iLastIndexTablePos to l_iLastIndexTablePos\r
+            end\r
+            increment l_iLastIndexTablePos\r
+            \r
+            send delete_data to (mTokens(current_object))\r
+            send set_string to (mTokens(current_object)) l_sIndexTable "|"\r
+            get token_count of (mTokens(current_object)) to l_iIndexValues\r
+            if (l_iLastIndexTablePos <= l_iIndexValues) begin\r
+                get token_value of (mTokens(current_object)) item l_iLastIndexTablePos to l_iIndex\r
+                set c_iLastIndexTableHash to l_iHash\r
+                set c_iLastIndexTablePos to l_iLastIndexTablePos\r
+            end\r
+            else begin\r
+                move -1 to l_iIndex\r
+                set c_iLastIndexTableHash to -1\r
+                set c_iLastIndexTablePos to -1\r
+            end\r
+        end\r
+\r
+        function_return l_iIndex\r
+    end_function\r
+    \r
+    function matrix_index_count_from_value string val returns integer\r
+        local integer l_iHashOn l_iHash l_iIndexValues\r
+        local string l_sIndexTable\r
+    \r
+        get c_iHashOn to l_iHashOn\r
+    \r
+        if (l_iHashOn <> -1) begin\r
+            get find_hash of (mHash_table(current_object)) item val to l_iHash\r
+            get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable\r
+    \r
+            send delete_data to (mTokens(current_object))\r
+            send set_string to (mTokens(current_object)) l_sIndexTable "|"\r
+            get token_count of (mTokens(current_object)) to l_iIndexValues\r
+        end\r
+    \r
+        function_return l_iIndexValues\r
+    end_function\r
+        \r
+    procedure set item_count integer newVal\r
+        forward set item_count to newVal\r
+    end_procedure\r
+        \r
+    procedure matrix_delete integer itemx integer itemy\r
+        local string l_sBuf l_sTmp l_sOldVal\r
+        local integer l_i l_iWidth l_iHashOn l_iHash\r
+\r
+        get c_iWidth to l_iWidth\r
+        get c_iHashOn to l_iHashOn\r
+    \r
+        forward get array_value item itemx to l_sBuf\r
+            \r
+        send delete_data to (mTokens(current_object))\r
+        send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+        \r
+        if (l_iHashOn = itemy) begin                \r
+            get token_value of (mTokens(current_object)) item itemy to l_sOldVal\r
+        end\r
+        set token_value of (mTokens(current_object)) item itemy to (character(3))\r
+\r
+        move "" to l_sBuf\r
+        for l_i from 0 to l_iWidth\r
+            get token_value of (mTokens(current_object)) item l_i to l_sTmp\r
+            if (length(l_sTmp) = 0) move (character(3)) to l_sTmp\r
+            if (length(l_sBuf) <> 0) append l_sBuf (character(1))\r
+            append l_sBuf l_sTmp\r
+        loop\r
+        move (replaces(character(3),l_sBuf,"")) to l_sBuf\r
+\r
+        forward set array_value item itemx to l_sBuf\r
+        \r
+        // Delete in the value to the hash\r
+        if (l_iHashOn = itemy) begin                \r
+            get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash\r
+            if (l_iHash <> 0) begin                     \r
+        get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp                    \r
+        if (l_sTmp contains ("|"+string(itemx)+"|")) begin\r
+            move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp\r
+            if (l_sTmp = "") begin\r
+                send remove_hash to (mHash_table(current_object)) l_iHash\r
+            end\r
+            else begin\r
+                if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp\r
+                else append l_sTmp "|"\r
+            end\r
+            set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+        end                             \r
+            end\r
+        end\r
+    end_procedure\r
+        \r
+    // Inefficient.\r
+    procedure delete_item integer itemx                \r
+        local string l_sBuf l_sOldVal l_sTmp l_sIndexTable\r
+        local integer l_iHashOn l_iHash l_i l_j l_iItems l_iIndexValues l_iIndex\r
+        \r
+        get c_iHashOn to l_iHashOn\r
+        // Delete in the value to the hash\r
+        if (l_iHashOn <> -1) begin\r
+            forward get array_value item itemx to l_sBuf\r
+            send delete_data to (mTokens(current_object))\r
+            send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+            get token_value of (mTokens(current_object)) item l_iHashOn to l_sOldVal\r
+            get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash\r
+            if (l_iHash <> 0) begin                     \r
+                get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                if (l_sTmp contains ("|"+string(itemx)+"|")) begin\r
+                    move (replace(("|"+string(itemx)+"|"),l_sTmp,"")) to l_sTmp\r
+                    if (l_sTmp = "") begin\r
+                        send remove_hash to (mHash_table(current_object)) l_iHash\r
+                    end\r
+                    else begin\r
+                        if (left(l_sTmp,1) <> "|") move ("|"+l_sTmp) to l_sTmp\r
+                        else append l_sTmp "|"\r
+                    end\r
+                    set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                end                     \r
+            end\r
+                \r
+            forward get item_count to l_iItems\r
+        \r
+            for l_i from (itemx+1) to l_iItems\r
+        \r
+                forward get array_value item l_i to l_sBuf\r
+                send delete_data to (mTokens(current_object))\r
+                send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+                get token_value of (mTokens(current_object)) item l_iHashOn to l_sOldVal\r
+                get find_hash of (mHash_table(current_object)) item l_sOldVal to l_iHash\r
+                \r
+                if (l_iHash <> 0) begin\r
+                    get string_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable\r
+                    \r
+                    send delete_data to (mTokens(current_object))\r
+                    send set_string to (mTokens(current_object)) l_sIndexTable "|"\r
+                    get token_count of (mTokens(current_object)) to l_iIndexValues\r
+                    move "|" to l_sIndexTable\r
+                    for l_j from 1 to l_iIndexValues\r
+                        get token_value of (mTokens(current_object)) item l_j to l_iIndex\r
+                        if (l_iIndex = l_i) calc (l_iIndex-1) to l_iIndex\r
+                        append l_sIndexTable (string(l_iIndex)+"|")\r
+                    loop\r
+                    \r
+                    set array_value of (mHash_array(current_object)) item l_iHash to l_sIndexTable\r
+                end\r
+            loop\r
+            \r
+        end\r
+            \r
+        forward send delete_item to current_object itemx\r
+    end_procedure\r
+\r
+    procedure matrix_sort integer itemy string order \r
+        local string l_sBuf l_sTmp l_sTmp2 l_sHash\r
+        local integer l_iX l_i l_j l_iMax l_iPoolMax l_iWidth l_iThrow l_iNumCount l_iHashOn l_iHash\r
+        \r
+        move (trim(uppercase(order))) to order\r
+        if ((order <> "ASCENDING") and (order <> "DESCENDING")) move "ASCENDING" to order\r
+        \r
+        object mSort_array is an array\r
+        end_object\r
+        object mClone_array is an array\r
+        end_object\r
+        \r
+        get c_iHashOn to l_iHashOn\r
+        get c_iWidth to l_iWidth\r
+        forward get item_count to l_iMax\r
+        \r
+        send delete_data to (mSort_array(current_object))\r
+        send delete_data to (mClone_array(current_object))\r
+        \r
+        if (l_iHashOn <> -1) begin\r
+            send delete_data to (mHash_array(current_object))\r
+        end\r
+        \r
+        move (l_iMax-1) to l_iMax       \r
+        \r
+        for l_i from 0 to l_iMax\r
+            forward get array_value item l_i to l_sBuf\r
+            \r
+            send delete_data to (mTokens(current_object))\r
+            send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+            get token_value of (mTokens(current_object)) item itemy to l_sTmp\r
+        \r
+            move 0 to l_iNumCount \r
+            for l_j from 1 to (length(l_sTmp))\r
+                if (((ascii(mid(l_sTmp,1,l_j))) >= 48) and ((ascii(mid(l_sTmp,1,l_j))) <= 57) or ((ascii(mid(l_sTmp,1,l_j))) = 46)) begin\r
+                    increment l_iNumCount\r
+                end\r
+            loop\r
+            if ((length(l_sTmp) > 0) and (length(l_sTmp) = l_iNumCount)) begin\r
+                set array_value of (mSort_array(current_object)) item l_i to (number(l_sTmp))\r
+            end\r
+            else begin\r
+                if (length(l_sTmp) = 0) move (character(2)) to l_sTmp\r
+                set array_value of (mSort_array(current_object)) item l_i to l_sTmp\r
+            end\r
+        loop\r
+        \r
+        if (order = "ASCENDING") send sort_items to (mSort_array(current_object)) ascending\r
+        if (order = "DESCENDING") send sort_items to (mSort_array(current_object)) descending\r
+\r
+        move l_iMax to l_iPoolMax\r
+\r
+        for l_i from 0 to l_iMax\r
+            get array_value of (mSort_array(current_object)) item l_i to l_sTmp\r
+            if (l_sTmp = character(2)) move "" to l_sTmp\r
+            \r
+            for l_j from 0 to l_iPoolMax\r
+                // Ideally we'd change the next 3 lines for a lookup table instead\r
+                forward get array_value item l_j to l_sBuf\r
+                \r
+                send delete_data to (mTokens(current_object))\r
+                send set_string to (mTokens(current_object)) l_sBuf (character(1))\r
+                get token_value of (mTokens(current_object)) item itemy to l_sTmp2\r
+                \r
+                if (l_sTmp = l_sTmp2) begin\r
+                    set array_value of (mClone_array(current_object)) item l_i to l_sBuf                    \r
+                    \r
+                    // On successful find shrink the sort pool here by moving max to l_j and decrementing max                 \r
+                    forward get array_value item l_iPoolMax to l_sBuf\r
+                    forward set array_value item l_j to l_sBuf\r
+                    forward send delete_item to current_object l_iPoolMax\r
+                    decrement l_iPoolMax                    \r
+                        \r
+                    // Remap hash\r
+                    if (l_iHashOn <> -1) begin                  \r
+                        get token_value of (mTokens(current_object)) item l_iHashOn to l_sHash\r
+                        get find_hash of (mHash_table(current_object)) item l_sHash to l_iHash\r
+                        get string_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                        if not (l_sTmp contains ("|"+string(l_i)+"|")) begin\r
+                            if (length(l_sTmp) = 0) move "|" to l_sTmp\r
+                            append l_sTmp (string(l_i)+"|")\r
+                            set array_value of (mHash_array(current_object)) item l_iHash to l_sTmp\r
+                        end\r
+                    end                    \r
+                    goto dirty_speedup_jump\r
+                end\r
+            loop\r
+            dirty_speedup_jump:\r
+        loop\r
+        send delete_data to (mSort_array(current_object))\r
+                \r
+        for l_i from 0 to l_iMax\r
+            get array_value of (mClone_array(current_object)) item l_i to l_sBuf\r
+            forward set array_value item l_i to l_sBuf                      \r
+        loop\r
+        \r
+        send destroy_object to (mSort_array(current_object))  // Use "send request_destroy_object" to destroy object and all children.\r
+        send destroy_object to (mClone_array(current_object))\r
+    end_procedure\r
+    \r
+end_class\r
+\r
+// Rss 2.0 data class - RFC-822 dates used\r
+//\r
+// Send message methods:\r
+//     init_rss                  - Initialise a new rss20 instance\r
+//     init_img                  - Initialise the image to be used in the feed\r
+//     add_item                  - Add an item to the feed\r
+//     write_rss                 - Write the feed out to disk\r
+//\r
+// Set methods:\r
+//    set_ttl                    - Set the TTL/refresh rate of the feed\r
+//    set_contacts               - Set admin contacts\r
+//    \r
+// Get methods:\r
+//\r
+// Example usage:\r
+//\r
+//    object test is an rss20\r
+//    end_object\r
+//\r
+//    move "" to link\r
+//    move "" to url\r
+//\r
+//    move "Google Maps" to title\r
+//    move ("http:/"+"/www.google.com/maps") to link\r
+//    move "Try out google maps" to desc\r
+//    send init_rss to (test(current_object)) title link desc\r
+//\r
+//    move ("http:/"+"/www.google.com/images/srpr/logo11w.png") to url\r
+//    move 19 to x\r
+//    move 41 to y\r
+//    send init_img to (test(current_object)) url x y\r
+//\r
+//    send set_ttl to (test(current_object)) 30\r
+//    send set_contacts to (test(current_object)) "maps@google.com" "search@google.com"\r
+//\r
+//    for i from 1 to 15\r
+//        move "Test item " to title\r
+//        append title i\r
+//        move ("http:/"+"/www.google.com") to link\r
+//        move "Test description " to desc\r
+//        append desc i\r
+//        move "NONE" to cat\r
+//\r
+//        send add_item to (test(current_object)) title link desc cat (rssdate((now("date")),(now("longtime"))))\r
+//    loop\r
+//    send write_rss to (test(current_object)) "c:\google_maps.rss"\r
+\r
+class rss20 is a matrix\r
+    procedure construct_object string argc \r
+        forward send construct_object argc\r
+        property string c_rssTitle\r
+        property string c_rssLink\r
+        property string c_rssDesc\r
+        \r
+        property string c_imgTitle\r
+        property string c_imgUrl\r
+        property string c_imgLink\r
+        property string c_imgDesc\r
+        \r
+        property string c_webMaster\r
+        property string c_manEditor\r
+        \r
+        property integer c_imgx\r
+        property integer c_imgy\r
+        property integer c_ttl\r
+        \r
+        property integer c_itemCount\r
+    end_procedure\r
+    \r
+    procedure init_rss string rssTitle string rssLink string rssDesc\r
+        set c_rssTitle to rssTitle\r
+        set c_rssLink to rssLink\r
+        set c_rssDesc to rssDesc\r
+        set c_itemCount to 0\r
+    end_procedure\r
+    \r
+    procedure init_img string imgUrl integer imgx integer imgy\r
+        local string imgTitle imgLink imgDesc\r
+        get c_rssTitle to imgTitle\r
+    get c_rssLink to imgLink\r
+    get c_rssDesc to imgDesc\r
+    \r
+        set c_imgTitle to imgTitle\r
+        set c_imgUrl to imgUrl\r
+        set c_imgLink to imgLink\r
+        set c_imgDesc to imgDesc\r
+        set c_imgx to imgx\r
+        set c_imgy to imgy\r
+    end_procedure\r
+    \r
+    procedure set_ttl integer ttl\r
+        if (ttl > 0) set c_ttl to ttl\r
+    end_procedure\r
+    \r
+    procedure set_contacts string webMaster string manEditor\r
+        if (webMaster <> "") set c_webMaster to webMaster\r
+        if (manEditor <> "") set c_manEditor to manEditor\r
+    end_procedure\r
+    \r
+    procedure add_item string itemTitle string itemLink string itemDesc string itemCat string pubDate string itemGuID\r
+        local integer l_itemCount\r
+        get c_itemCount to l_itemCount\r
+    \r
+        // The standard says we should not have more than 15 items, but ignore this.\r
+        //if ((l_itemCount < 15) and (itemTitle <> "")) begin \r
+        if (itemTitle <> "") begin\r
+            increment l_itemCount\r
+            set c_itemCount to l_itemCount\r
+            \r
+            forward set matrix_value item l_itemCount item 0 to itemTitle\r
+            forward set matrix_value item l_itemCount item 1 to itemLink\r
+            forward set matrix_value item l_itemCount item 2 to itemDesc\r
+            forward set matrix_value item l_itemCount item 3 to itemCat\r
+            forward set matrix_value item l_itemCount item 4 to itemGuID\r
+            if ((pubDate <> "") and (pubDate <> "NOW")) forward set matrix_value item l_itemCount item 6 to pubDate\r
+        end\r
+    end_procedure\r
+    \r
+    procedure write_rss string rssFileName\r
+        local string l_rssTitle l_rssLink l_rssDesc l_imgTitle l_imgUrl l_imgLink l_itemTitle l_itemLink l_itemDesc l_itemCat l_sConflict l_property l_manEditor l_webMaster l_pubDate l_itemGuID l_itemCc\r
+        local integer l_imgx l_imgy l_itemcount l_i l_j l_iConflict l_iTtl\r
+        \r
+        get c_rssTitle to l_rssTitle\r
+        get c_rssLink to l_rssLink\r
+        get c_rssDesc to l_rssDesc\r
+    \r
+        get c_imgTitle to l_imgTitle\r
+        get c_imgUrl to l_imgUrl\r
+        get c_imgLink to l_imgLink\r
+        get c_manEditor to l_manEditor\r
+        get c_webMaster to l_webMaster\r
+        \r
+        get c_imgx to l_imgx\r
+        get c_imgy to l_imgy\r
+        get c_itemCount to l_itemCount\r
+        get c_ttl to l_iTtl\r
+    \r
+        direct_output channel default_file_channel rssFileName\r
+            writeln channel default_file_channel '<?xml version="1.0" ?>'\r
+            writeln channel default_file_channel '<?xml-stylesheet type="text/xsl" href="rss.xsl" media="screen"?>'\r
+            write channel default_file_channel '<rss version="2.0" xmlns:dc="http:/' '/purl.org/dc/elements/1.1/" xmlns:sy="http:/'\r
+            write channel default_file_channel '/purl.org/rss/1.0/modules/syndication/" xmlns:admin="http:/' '/webns.net/mvcb/" xmlns:rdf="http:/'\r
+            writeln channel default_file_channel '/www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http:/' '/purl.org/rss/1.0/modules/content/">'\r
+            \r
+            // skipHours skipDays cloud - all currently not used\r
+            // Write out Channel\r
+            writeln channel default_file_channel '       <channel>'\r
+            writeln channel default_file_channel '               <title>' (trim(l_rssTitle)) '</title>'\r
+            writeln channel default_file_channel '               <link>' (trim(l_rssLink)) '</link>'\r
+            writeln channel default_file_channel '               <description>' (trim(l_rssDesc)) '</description>'\r
+            writeln channel default_file_channel '               <language>en-gb</language>'\r
+            writeln channel default_file_channel '               <generator>Df32func RSS Object Generator</generator>'\r
+            writeln channel default_file_channel '               <copyright>Copyright ' (trim(l_rssTitle)) ' (C) ' (now("date")) '</copyright>'\r
+            writeln channel default_file_channel '               <lastBuildDate>' (rssdate((now("date")),(now("longtime")))) '</lastBuildDate>'\r
+            writeln channel default_file_channel '               <pubDate>' (rssdate((now("date")),(now("longtime")))) '</pubDate>'\r
+            \r
+            if (l_manEditor <> "") writeln channel default_file_channel '               <managingEditor>' l_manEditor '</managingEditor>'\r
+            if (l_webMaster <> "") writeln channel default_file_channel '               <webMaster>' l_webMaster '</webMaster>'\r
+            if (l_iTtl <> 0) writeln channel default_file_channel '               <ttl>' l_iTtl '</ttl>'           \r
+            \r
+            // Write out image\r
+            if ((l_imgUrl <> "") and (l_imgx > 0) and (l_imgy > 0)) begin\r
+                writeln channel default_file_channel '               <image>'\r
+                writeln channel default_file_channel '                       <title>' (trim(l_imgTitle)) '</title>'\r
+                writeln channel default_file_channel '                       <url>' (trim(l_imgUrl)) '</url>'\r
+                writeln channel default_file_channel '                       <link>' (trim(l_imgLink)) '</link>'\r
+                writeln channel default_file_channel '                       <height>' l_imgx '</height>'\r
+                writeln channel default_file_channel '                       <width>' l_imgy '</width>'\r
+                writeln channel default_file_channel '                       <description>' (trim(l_rssDesc)) '</description>'\r
+                writeln channel default_file_channel '               </image>'\r
+            end\r
+            \r
+            // Write out items\r
+            for l_i from 1 to l_itemCount\r
+                forward get matrix_value item l_i item 0 to l_itemTitle\r
+                forward get matrix_value item l_i item 1 to l_itemLink\r
+                forward get matrix_value item l_i item 2 to l_itemDesc\r
+                forward get matrix_value item l_i item 3 to l_itemCat\r
+                forward get matrix_value item l_i item 4 to l_itemGuID\r
+                forward get matrix_value item l_i item 5 to l_itemCc\r
+                forward get matrix_value item l_i item 6 to l_pubDate\r
+                    \r
+\r
+                // Escape html in the description\r
+                move (replaces('"',l_itemDesc,"&quot;")) to l_itemDesc\r
+                move (replaces('<',l_itemDesc,"&lt;")) to l_itemDesc\r
+                move (replaces('>',l_itemDesc,"&gt;")) to l_itemDesc\r
+                \r
+                writeln channel default_file_channel '               <item>'\r
+                writeln channel default_file_channel '                      <title>' l_itemTitle '</title>'\r
+                writeln channel default_file_channel '                      <link>' l_itemLink '</link>'\r
+                writeln channel default_file_channel '                      <description>' l_itemDesc '</description>'\r
+                \r
+                if (l_itemGuID = "") begin\r
+                move 0 to l_iConflict\r
+                for l_j from 1 to (l_i-1)\r
+                    forward get matrix_value item l_j item 1 to l_sConflict\r
+                    if (l_sConflict = l_itemLink) increment l_iConflict\r
+                end\r
+                    if (l_iConflict > 0) append l_iTemLink "#" l_iConflict\r
+                end\r
+                if (l_itemGuID <> "") append l_itemLink "#" l_itemGuID\r
+                \r
+                writeln channel default_file_channel '                      <guid isPermaLink="false">' l_itemLink '</guid>'\r
+                if ((l_pubDate = "") or (l_pubDate = "NOW")) writeln channel default_file_channel '                      <pubDate>' (rssdate((now("date")),(now("longtime")))) '</pubDate>'\r
+                else writeln channel default_file_channel '                      <pubDate>' l_pubDate '</pubDate>'\r
+                writeln channel default_file_channel '                      <category>' l_itemCat '</category>'\r
+                writeln channel default_file_channel '               </item>'          \r
+            loop\r
+            \r
+            // Write out file/channel close\r
+            writeln channel default_file_channel '       </channel>'\r
+            writeln channel default_file_channel '</rss>'  \r
+        close_output channel default_file_channel\r
+        \r
+    end_procedure        \r
+    \r
+end_class\r
+\r
+\r
+// File list - Returns the contents of the DataFlex filelist\r
+//\r
+// In order to retrieve file attributes including the file number the file needs to be opened.\r
+//\r
+// Send message methods:\r
+//    init                  - Initialize the matrix by reading the filelist\r
+//\r
+// Set methods:\r
+//    <na>\r
+//\r
+// Get methods:\r
+//    item_count            - Return the count of filelist items\r
+//    root_name             - Get the root name of the file\r
+//    display_name          - Get the user friendly name of the file\r
+//    system_name           - Get the DataFlex friendly name of the table / file\r
+//    valid                 - Non-zero if the DataFlex FD file exists\r
+//\r
+// Example usage:\r
+//\r
+//    object test is a filelist\r
+//    end_object\r
+\r
+//    integer x i \r
+//    string buf1 buf2 buf3 buf4\r
+//    send init to (test(current_object)) "c:\df32" "filelist.cfg"\r
+//    get item_count of test to x\r
+//    \r
+//    for i from 0 to x\r
+//        get root_name of (test(current_object)) item i to buf1\r
+//        get display_name of (test(current_object)) item i to buf2\r
+//        get system_name of (test(current_object)) item i to buf3\r
+//        get valid of (test(current_object)) item i to buf4\r
+//        showln buf1 " " buf2 " " buf3 " " buf4\r
+//    loop\r
+//\r
+\r
+class filelist is a matrix\r
+    procedure construct_object string argc \r
+            forward send construct_object argc\r
+            property string c_filelistDirectory\r
+            property string c_filelistName\r
+            property integer c_itemCount\r
+    end_procedure\r
+    \r
+    function item_count returns integer\r
+        local integer l_iItems\r
+        get c_itemCount to l_iItems\r
+        function_return l_iItems\r
+    end_function\r
+    \r
+    procedure init string filelistDirectory string filelistName\r
+        local integer l_iFileNumber\r
+        local string l_sRootName l_sUserDisplayName l_sFileName l_sHead l_sUrn\r
+        \r
+        move 0 to l_iFileNumber\r
+        if (filelistName = "") begin\r
+            move "filelist.cfg" to filelistName\r
+        end\r
+        \r
+        set c_filelistDirectory to filelistDirectory\r
+        set c_filelistName to filelistName\r
+        \r
+        direct_input channel default_file_channel (filelistDirectory+filelistName)\r
+            read_block l_sHead 256          \r
+            while not (seqeof)          \r
+                //Block of 128 split 41\33\54\r
+                read_block channel default_file_channel l_sRootName 41\r
+                read_block channel default_file_channel l_sUserDisplayName 33\r
+                read_block channel default_file_channel l_sFileName 54\r
+\r
+                move filelistDirectory to l_sUrn\r
+                append l_sUrn (trim(cstring(l_sFileName))) ".FD"\r
+\r
+                if ((trim(cstring(l_sFileName))) <> "") begin\r
+                    forward set matrix_value item l_iFileNumber item 0 to (trim(cstring(l_sRootName)))\r
+                    forward set matrix_value item l_iFileNumber item 1 to (trim(cstring(l_sUserDisplayName)))\r
+                    forward set matrix_value item l_iFileNumber item 2 to (trim(cstring(l_sFileName)))\r
+                    if (does_exist(l_sUrn) = 1) begin\r
+                        forward set matrix_value item l_iFileNumber item 3 to 1\r
+                    end\r
+                    else begin\r
+                        forward set matrix_value item l_iFileNumber item 3 to 0\r
+                    end\r
+                    increment l_iFileNumber\r
+                end\r
+            loop        \r
+        close_input channel default_file_channel\r
+    \r
+        set c_itemCount to l_iFileNumber\r
+    end_procedure\r
+    \r
+    function root_name integer itemx returns integer\r
+        local string l_sBuf\r
+        forward get matrix_value item itemx item 0 to l_sBuf\r
+        function_return l_sBuf\r
+    end_function\r
+        \r
+    function display_name integer itemx returns integer\r
+        local string l_sBuf\r
+        forward get matrix_value item itemx item 1 to l_sBuf\r
+        function_return l_sBuf\r
+    end_function\r
+\r
+    function system_name integer itemx returns integer\r
+        local string l_sBuf\r
+        forward get matrix_value item itemx item 2 to l_sBuf\r
+        function_return l_sBuf\r
+    end_function\r
+    \r
+    function valid integer itemx returns integer\r
+        local integer l_iTmp\r
+        forward get matrix_value item itemx item 3 to l_iTmp\r
+        function_return l_iTmp\r
+    end_function\r
+end_class\r
+\r
+\r
+//Class for reading unicode files when we know they have low ASCII only\r
+//\r
+// Example Usage:\r
+//\r
+//    object test is a UnicodeReader\r
+//    end_object\r
+//\r
+//    local string asciiline\r
+//    local integer error i count channelx\r
+//\r
+//    send open_file to (test(current_object)) 1 "c:\test_unicode.txt"\r
+//    while not (seqeof)\r
+//        get readline of (test(current_object)) 1 to asciiline\r
+//        showln asciiline\r
+//    loop\r
+//    send close_file to (test(current_object)) 1\r
+\r
+class UnicodeReader is an array\r
+    procedure construct_object integer argc\r
+        forward send construct_object\r
+        property integer c_iSizeBytes public argc\r
+        property integer c_iBytesOn                \r
+        property integer c_iOpen\r
+        property string c_sPeek\r
+        set c_iOpen to 0\r
+    end_procedure\r
+        \r
+    procedure open_file integer l_iChan string l_sFile\r
+        local integer l_iSizeBytes l_iOpen\r
+        local string l_sTmp l_sBom\r
+        get c_iOpen to l_iOpen\r
+            \r
+        move (trim(l_sFile)) to l_sFile\r
+        if ((l_sFile <> "") and (l_iOpen = 0)) begin    \r
+            move (file_size_bytes(l_sFile)-2) to l_iSizeBytes\r
+            direct_input channel l_iChan l_sFile\r
+                read_block channel l_iChan l_sTmp 1\r
+                if (ascii(l_sTmp) < 254) begin\r
+                    set_channel_position l_iChan to 0\r
+                end\r
+                else begin\r
+                    read_block channel l_iChan l_sTmp 1\r
+                end\r
+            \r
+                set c_iSizeBytes to l_iSizeBytes\r
+                set c_iBytesOn to 0\r
+                set c_iOpen to 1\r
+        end\r
+    end_procedure\r
+        \r
+    procedure close_file integer l_iChan\r
+        local integer l_iOpen\r
+        \r
+        get c_iOpen to l_iOpen\r
+        if (l_iOpen = 0) begin  \r
+            close_input channel l_iChan\r
+        end\r
+        set c_iOpen to 0\r
+    end_procedure\r
+    \r
+    function readline global integer l_iChan returns string\r
+        local string l_sReturn l_sTmp\r
+        local integer l_iBytesOn l_iSizeBytes\r
+        \r
+        move "" to l_sTmp\r
+        move "" to l_sReturn\r
+        get c_iSizeBytes to l_iSizeBytes\r
+        get c_iBytesOn to l_iBytesOn\r
+        \r
+        while ((l_sTmp <> character(13)) and (l_iBytesOn < l_iSizeBytes))\r
+            read_block channel l_iChan l_sTmp 1\r
+            increment l_iBytesOn\r
+            if ((l_sTmp <> character(13)) and (l_sTmp <> character(10)) and (l_sTmp <> character(0))) begin\r
+                move (l_sReturn+l_sTmp) to l_sReturn\r
+            end\r
+        loop\r
+    \r
+        function_return l_sReturn\r
+    end_function\r
+    \r
+end_class\r
+\r
+// ListDirectory class - provides a directory listing\r
+//\r
+// Send message methods:\r
+//    delete_data           - Clear the listing\r
+//    list_files            - Read the directory listing into the object\r
+//    sort_files            - Sort the file list on a particular property\r
+//\r
+// Set methods:\r
+//    <na>\r
+//\r
+// Get methods:\r
+//    file_count            - Return the count of files in the list\r
+//    filename              - Get the base name of a file in the list\r
+//    filesize              - Get the size of a file in the list\r
+//    file_created          - Get the created timestamp of the file\r
+//    file_modified         - Get the modification timestamp of the file\r
+//    file_accessed         - Get the last access timestamp of the file\r
+//\r
+// Example usage:\r
+//\r
+//    object test is a ListDirectory\r
+//    end_object\r
+//    \r
+//    integer i x\r
+//    string buf tmp\r
+//    \r
+//    send delete_data to test\r
+//    send list_files to (test(current_object)) "c:\*"\r
+//    get file_count of (test(current_object)) to x\r
+//    send sort_files to test "file_accesed" "ASCENDING"\r
+//    \r
+//    for i from 0 to x\r
+//        get filename of (test(current_object)) item i to tmp\r
+//        get filesize of (test(current_object)) item i to buf\r
+//        append tmp "," buf\r
+//        move (pad(tmp,35)) to tmp\r
+//        get file_created of (test(current_object)) item i to buf\r
+//        append tmp "," buf\r
+//        get file_modified of (test(current_object)) item i to buf\r
+//        append tmp "," buf\r
+//        get file_accessed of (test(current_object)) item i to buf\r
+//        append tmp "," buf\r
+//        showln tmp\r
+//    loop    \r
+\r
+class ListDirectory is a matrix\r
+    procedure construct_object integer argc\r
+        forward send construct_object argc\r
+        property integer c_iFiles public argc\r
+    end_procedure\r
+    \r
+    procedure delete_data\r
+        set c_iFiles to 0\r
+        forward send delete_data\r
+    end_procedure\r
+    \r
+    procedure list_files string sPathName\r
+        local string sWin32FindData sLine sLast sComment sFileName sModifiedDate sAccessDate sCreationDate k sLastFile\r
+        local integer l_01iResult iFileSize l_iFiles\r
+        local pointer pT5 pT6\r
+        local handle hFile\r
+        local dword dwFileSizeHigh dwFileSizeLow dwHighDateTime dwLowDateTime\r
+\r
+        forward send delete_data\r
+        \r
+        zerotype _WIN32_FIND_DATA to sWin32FindData\r
+        getaddress of sWin32FindData to pT5\r
+        move (trim(sPathName)) to sPathName\r
+        getaddress of sPathName to pT6\r
+        move (FindFirstFile(pT6, pT5)) to hFile\r
+        //if (hFile = -1) showln "Invalid file handle!"\r
+\r
+        move -1 to l_iFiles\r
+        repeat \r
+            // FileName\r
+            getbuff_String from sWin32FindData at WIN32_FIND_DATA.cFileName to sFileName\r
+            if ((sFileName <> ".") and (sFileName <> "..") and (sFileName <> "")) begin\r
+                increment l_iFiles\r
+\r
+                // FileSize\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeHigh to dwFileSizeHigh\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeLow to dwFileSizeLow\r
+                moveint ((dwFileSizeHigh*MaxDword)+dwFileSizeLow) to iFileSize\r
+\r
+                // File Modified Time\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteLowDateTime to dwLowDateTime\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteHighDateTime to dwHighDateTime\r
+                move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sModifiedDate\r
+\r
+                // File Accessed Time\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessLowDateTime to dwLowDateTime\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessHighDateTime to dwHighDateTime\r
+                move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sAccessDate\r
+\r
+                // File Creation Time\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationLowDateTime to dwLowDateTime\r
+                getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationHighDateTime to dwHighDateTime\r
+                move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sCreationDate\r
+\r
+                move (cstring(sFileName)) to sFileName\r
+                forward set matrix_value item l_iFiles item 1 to sFileName\r
+                forward set matrix_value item l_iFiles item 2 to iFileSize\r
+                forward set matrix_value item l_iFiles item 3 to (integer(date(sModifiedDate)))\r
+                forward set matrix_value item l_iFiles item 4 to (integer(date(sAccessDate)))\r
+                forward set matrix_value item l_iFiles item 5 to (integer(date(sCreationDate)))\r
+            end\r
+            zerotype _WIN32_FIND_DATA to sWin32FindData\r
+            move (FindNextFile(hFile, pT5)) to l_01iResult\r
+        until (l_01iResult = 0)\r
+        move (FindClose(hFile)) to l_01iResult\r
+\r
+        set c_iFiles to l_iFiles\r
+    end_procedure\r
+\r
+    function filename integer itemx returns string\r
+        local string l_sBuf\r
+        move "" to l_sBuf\r
+        forward get matrix_value item itemx item 1 to l_sBuf\r
+        function_return l_sBuf\r
+    end_function \r
+    \r
+    function filesize integer itemx returns integer\r
+            local integer l_iBuf                \r
+            forward get matrix_value item itemx item 2 to l_iBuf\r
+            function_return l_iBuf\r
+    end_function\r
+    \r
+    function file_modified integer itemx returns date\r
+        local integer l_iBuf                \r
+        forward get matrix_value item itemx item 3 to l_iBuf\r
+        function_return (date(l_iBuf))\r
+    end_function\r
+    \r
+    function file_accessed integer itemx returns date\r
+        local integer l_iBuf                \r
+        forward get matrix_value item itemx item 4 to l_iBuf\r
+        function_return (date(l_iBuf))\r
+    end_function \r
+    \r
+    function file_created integer itemx returns date\r
+        local integer l_iBuf                \r
+        forward get matrix_value item itemx item 5 to l_iBuf\r
+        function_return (date(l_iBuf))\r
+    end_function\r
+    \r
+    procedure sort_files string sField string sOrder\r
+        local integer l_iSort\r
+        if ((sOrder <> "ASCENDING") and (sOrder <> "DESCENDING")) move "ASCENDING" to sOrder\r
+        move 1 to l_iSort\r
+        if (sField = "filename") move 1 to l_iSort\r
+        if (sField = "filesize") move 2 to l_iSort\r
+        if (sField = "file_modified") move 3 to l_iSort\r
+        if (sField = "file_accessed") move 4 to l_iSort\r
+        if (sField = "file_created") move 5 to l_iSort\r
+        forward send matrix_sort l_iSort sOrder\r
+    end_procedure\r
+    \r
+    function file_count returns integer\r
+        local integer l_iFiles\r
+        get c_iFiles to l_iFiles\r
+        function_return l_iFiles\r
+    end_function\r
+end_class\r
+\r
+// ProcessList class - provides a listing of running processes\r
+//\r
+// Experimental; all aspects reading process info appear to fail, it can\r
+// be useful however to check if a particular process pid is still running.\r
+//\r
+// Send message methods:\r
+//    delete_data           - Clear the listing\r
+//    init_processes        - Read the process list table\r
+//\r
+// Set methods:\r
+//    <na>\r
+//\r
+// Get methods:\r
+//    get_process_id        - Return the PID of a particular process\r
+//    process_count         - Return count of processes in the list\r
+//    process_handle        - BROKEN\r
+//\r
+// Example usage:\r
+//\r
+//    object test is an ProcessList\r
+//    end_object\r
+//    \r
+//    integer i x id hx\r
+//    \r
+//    send init_processes to test\r
+//    get process_count of (test(current_object)) to x\r
+//    showln "Processes in list = "  x\r
+//    \r
+//    for i from 0 to x\r
+//        get process_id of (test(current_object)) item i to id\r
+//    loop\r
+//\r
+class ProcessList is an array\r
+    procedure construct_object integer argc\r
+            forward send construct_object\r
+            property integer c_iProcesses public argc\r
+    end_procedure\r
+    \r
+    procedure delete_data\r
+        set c_iProcesses to 0\r
+        forward send delete_data\r
+    end_procedure\r
+    \r
+    procedure init_processes\r
+    local string l_sProcesses l_sStructBytesBack l_sBuf l_sModules\r
+    local integer l_iThrow l_iBytes l_iBytes2 l_iBytesBack l_iBytesBack2 l_i l_j l_iPid l_iMid l_iProcesses\r
+    local pointer l_pProcesses l_pBytesBack l_pBytesBack2 l_pModules\r
+    local handle l_hProcess\r
+\r
+    move (1024*10) to l_iBytes  \r
+    zerostring l_iBytes to l_sProcesses\r
+    move 0 to l_iBytesBack\r
+    move 0 to l_iProcesses\r
+    forward send delete_data\r
+\r
+    getAddress of l_sProcesses to l_pProcesses  \r
+    zerotype _STRUCTBYTESBACK to l_sStructBytesBack\r
+    getaddress of l_sStructBytesBack to l_pBytesBack\r
+\r
+    move (EnumProcesses(l_pProcesses,l_iBytes,l_pBytesBack)) to l_iThrow\r
+\r
+    getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack\r
+\r
+    if (mod(l_iBytesBack,4) = 0) begin\r
+        for l_i from 1 to (l_iBytesBack/4)\r
+            move (left(l_sProcesses,4)) to l_sBuf\r
+            move (mid(l_sProcesses,(length(l_sProcesses)-4),5)) to l_sProcesses\r
+            getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iPid     \r
+            move (OpenProcess(PROCESS_QUERY_INFORMATION, 0,l_iPid)) to l_hProcess\r
+            \r
+            // Fails to open the process for more info here unfortunately\r
+            //showln "LERR=" (get_last_error_detail(GetLastError())) " " l_ipid\r
+\r
+            move 1024 to l_iBytes2\r
+            zerostring l_iBytes2 to l_sModules\r
+            getAddress of l_sModules to l_pModules\r
+            zerotype _STRUCTBYTESBACK to l_sStructBytesBack\r
+            getaddress of l_sStructBytesBack to l_pBytesBack2\r
+\r
+            move (EnumProcessModules(l_hProcess,l_pModules,l_iBytes2,l_pBytesBack2)) to l_iThrow\r
+            getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack2\r
+            \r
+            increment l_iProcesses              \r
+            forward set array_value item (l_i-1) to (string(l_iPid)+"|"+string(l_hProcess))\r
+\r
+            if (mod(l_iBytesBack2,4) = 0) begin\r
+                for l_j from 1 to (l_iBytesBack2/4)\r
+                    move (left(l_sModules,4)) to l_sBuf\r
+                    move (mid(l_sModules,(length(l_sModules)-4),5)) to l_sModules\r
+                    getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iMid\r
+                loop\r
+            end\r
+            move (CloseHandle(l_hProcess)) to l_iThrow\r
+        loop\r
+        \r
+        set c_iTokenOn to 0\r
+        set c_iProcesses to l_iProcesses\r
+    end\r
+    end_procedure\r
+\r
+    function process_id integer itemx returns integer\r
+        local string l_sBuf                \r
+        forward get array_value item itemx to l_sBuf\r
+        function_return (integer(left(l_sBuf,pos("|",l_sBuf)-1)))\r
+    end_function \r
+\r
+    // There's not much point to this as we couldn't get the handle because OpenProcess failed.\r
+    function process_handle integer itemx returns integer\r
+        local string l_sBuf                \r
+        forward get array_value item itemx to l_sBuf\r
+        function_return (integer(right(l_sBuf,length(l_sBuf)-pos("|",l_sBuf))))\r
+    end_function \r
+    \r
+    function process_count returns integer\r
+        local integer l_iProcesses\r
+        get c_iProcesses to l_iProcesses\r
+        function_return l_iProcesses\r
+    end_function\r
+end_class\r
diff --git a/src/df32/date.inc b/src/df32/date.inc
new file mode 100644 (file)
index 0000000..fe997e5
--- /dev/null
@@ -0,0 +1,368 @@
+//-------------------------------------------------------------------------\r
+// date.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to provide extended date manipulation capabilities.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/date.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Returns day of the week as an integer score 1 = monday 7 = sunday\r
+function get_day_score global date argv returns integer\r
+    local integer l_01tmpInt\r
+    \r
+    calc (mod(argv,7)) to l_01tmpInt\r
+    if (l_01tmpInt < 0) calc (l_01tmpInt+7) to l_01tmpInt\r
+    \r
+    case begin\r
+        case (l_01tmpInt = 3) move 1 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 4) move 2 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 5) move 3 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 6) move 4 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 0) move 5 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 1) move 6 to l_01tmpInt\r
+        case break\r
+        case (l_01tmpInt = 2) move 7 to l_01tmpInt\r
+        case break\r
+    case end\r
+    \r
+    function_return l_01tmpInt\r
+end_function\r
+\r
+// Returns the current day as a string from the date\r
+function get_day global date argv returns string\r
+    local integer l_iDay\r
+    local string l_sDay\r
+\r
+    move (get_day_score(argv)) to l_iDay\r
+    \r
+    case begin\r
+        case (l_iDay = 1) move "Monday" to l_sDay\r
+        case break\r
+        case (l_iDay = 2) move "Tuesday" to l_sDay\r
+        case break\r
+        case (l_iDay = 3) move "Wednesday" to l_sDay\r
+        case break\r
+        case (l_iDay = 4) move "Thursday" to l_sDay\r
+        case break\r
+        case (l_iDay = 5) move "Friday" to l_sDay\r
+        case break\r
+        case (l_iDay = 6) move "Saturday" to l_sDay\r
+        case break\r
+        case (l_iDay = 7) move "Sunday" to l_sDay\r
+        case break\r
+   case end\r
+\r
+    function_return l_sDay\r
+end_function\r
+\r
+// Returns the current month as a string from the date\r
+function get_month global date argv returns string\r
+    local integer l_iMonth\r
+    local string l_sMonth\r
+\r
+    calc ((integer(mid(argv, 2, 4)))-1) to l_iMonth\r
+    case begin\r
+        case (l_iMonth = 0) move "January" to l_sMonth\r
+        case (l_iMonth = 1) move "February" to l_sMonth\r
+        case (l_iMonth = 2) move "March" to l_sMonth\r
+        case (l_iMonth = 3) move "April" to l_sMonth\r
+        case (l_iMonth = 4) move "May" to l_sMonth\r
+        case (l_iMonth = 5) move "June" to l_sMonth\r
+        case (l_iMonth = 6) move "July" to l_sMonth\r
+        case (l_iMonth = 7) move "August" to l_sMonth\r
+        case (l_iMonth = 8) move "September" to l_sMonth\r
+        case (l_iMonth = 9) move "October" to l_sMonth\r
+        case (l_iMonth = 10) move "November" to l_sMonth\r
+        case (l_iMonth = 11) move "December"  to l_sMonth\r
+   case end\r
+\r
+    function_return l_sMonth\r
+end_function\r
+\r
+// Returns the current day of the month\r
+function get_day_of global date argv returns string\r
+    local string l_01tmpStr\r
+    local integer l_01tmpInt\r
+\r
+    move (mid(argv, 2, 1)) to l_01tmpInt\r
+    move "th" to l_01tmpStr\r
+    if (mid(argv, 1, 1)) ne 1 begin\r
+        if (mid(argv, 1, 2)) eq 1 move "st" to l_01tmpStr\r
+        if (mid(argv, 1, 2)) eq 2 move "nd" to l_01tmpStr\r
+        if (mid(argv, 1, 2)) eq 3 move "rd" to l_01tmpStr\r
+    end\r
+\r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Returns a string representing the full date e.g. "Friday 31st July 2009"\r
+function fulldate global date argv returns string\r
+    local string l_01tmpStr l_02tmpStr \r
+    local integer l_01tmpInt l_01arrayindex\r
+\r
+    move (get_day(argv)) to l_02tmpStr\r
+    move (mid(argv, 2, 1)) to l_01tmpInt\r
+    move "th" to l_01tmpStr\r
+    if (mid(argv, 1, 1)) ne 1 begin\r
+        if (mid(argv, 1, 2)) eq 1 move "st" to l_01tmpStr\r
+        if (mid(argv, 1, 2)) eq 2 move "nd" to l_01tmpStr\r
+        if (mid(argv, 1, 2)) eq 3 move "rd" to l_01tmpStr\r
+    end\r
+    append l_02tmpStr " " l_01tmpInt (trim(l_01tmpStr)) " "\r
+    move (get_month(argv)) to l_01tmpStr\r
+    append l_02tmpStr (trim(l_01tmpStr)) " " (trim(mid(argv, 4, 7)))\r
+\r
+    function_return l_02tmpStr\r
+end_function\r
+\r
+// Returns a string representing the date in short form e.g. "31 July 2009"\r
+function shortdate global date argv returns string\r
+    local string l_01tmpStr\r
+\r
+    move "" to l_01tmpStr\r
+    append l_01tmpStr (mid(argv,2,1)) " " (get_month(argv)) " " (mid(argv,4,7))\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Returns the current time and or date in different formats\r
+function now global string argv returns string\r
+    local string l_01tmpStr l_02tmpStr\r
+    local date l_01nowDate\r
+    local number l_01nowTime l_02nowTime l_03nowTime l_01nowSecs\r
+    sysdate l_01nowDate\r
+    calc ((number(strlen))+((number(strmark))/100)) to l_01nowTime\r
+    move "" to l_01tmpStr\r
+    if ((trim(lowercase(argv))) = "time") append l_01tmpStr (string(decround(l_01nowTime,2)))\r
+    if (((trim(lowercase(argv))) = "longtime") or ((trim(lowercase(argv))) = "timestamp")) begin\r
+        sysdate l_01nowDate l_01nowTime l_02nowTime l_03nowTime\r
+        move "" to l_01tmpStr\r
+        if ((trim(lowercase(argv))) = "timestamp") append l_01tmpStr l_01nowDate " "\r
+        if (l_01nowTime < 10) append l_01tmpStr 0\r
+        append l_01tmpStr l_01nowTime ":"\r
+        if (l_02nowTime < 10) append l_01tmpStr 0\r
+        append l_01tmpStr l_02nowTime ":"\r
+        if (l_03nowTime < 10) append l_01tmpStr 0\r
+        append l_01tmpStr l_03nowTime\r
+    end\r
+    if ((trim(lowercase(argv))) = "seconds") begin\r
+        sysdate l_01nowDate l_01nowTime l_02nowTime l_03nowTime\r
+        move (string((l_01nowTime*3600)+(l_02nowTime*60)+l_03nowTime)) to l_01tmpStr \r
+    end\r
+    if ((trim(lowercase(argv))) = "date") append l_01tmpStr l_01nowDate\r
+    if ((trim(lowercase(argv))) = "shorttimestamp") append l_01tmpStr l_01nowDate "," (string(decround(l_01nowTime,2)))\r
+    if ((trim(lowercase(argv))) = "longtimestamp") begin\r
+        append l_01tmpStr (fulldate(l_01nowDate)) " at "\r
+        if (l_01nowTime > 12) append l_01tmpStr (string(decround(l_01nowTime-12,2))) "PM"\r
+        if (l_01nowTime <= 12) append l_01tmpStr (string(decround(l_01nowTime,2))) "AM"\r
+    end\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Return a date and time in the RSS standard format\r
+function rssdate global date argv string argv2 returns string\r
+    local string l_01tmpStr\r
+\r
+    move "" to l_01tmpStr\r
+    append l_01tmpStr (left((get_day(argv)),3)) ", " (mid(argv,2,1)) " " (left((get_month(argv)),3)) " " (mid(argv,4,7)) " " (trim(argv2)) " GMT"\r
+    move (uppercase(l_01tmpStr)) to l_01tmpStr\r
+\r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Retuns a date in the format CCYYMMDD\r
+function cymd global date argv returns string\r
+    local string l_01tmpStr\r
+    \r
+    move (mid(argv,4,7)) to l_01tmpStr\r
+    append l_01tmpStr (mid(argv,2,4)) (mid(argv,2,1))\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Retuns a date in the format CCYY-MM-DD\r
+function sqldate global date argv returns string\r
+    local string l_01tmpStr\r
+    move "" to l_01tmpStr\r
+    \r
+    if (argv <> "") begin\r
+        move (mid(argv,4,7)) to l_01tmpStr\r
+        append l_01tmpStr "-" (mid(argv,2,4)) "-" (mid(argv,2,1))\r
+    end\r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Retuns a timestamp in the format CCYY-MM-DD HH:mm:SS\r
+function sqltimestamp global date argv integer argv2 integer argv3 integer argv4 returns string\r
+    local string l_01tmpStr\r
+    move "" to l_01tmpStr\r
+            \r
+    if ((argv <> "") and ((argv2 >= 0) and (argv2 <= 23)) and ((argv3 >= 0) and (argv3 <= 59)) and ((argv4 >= 0) and (argv4 <= 59))) begin\r
+        move (mid(argv,4,7)) to l_01tmpStr\r
+        append l_01tmpStr "-" (mid(argv,2,4)) "-" (mid(argv,2,1)) " "  (zeropad(argv2,2)) ":" (zeropad(argv3,2)) ":" (zeropad(argv4,2))\r
+    end\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Retuns a timestamp in the format DD/MM/CCYY HH:mm:SS\r
+function dftimestamp global date argv integer argv2 integer argv3 integer argv4 returns string\r
+    local string l_01tmpStr\r
+    move "" to l_01tmpStr\r
+            \r
+    if ((argv <> "") and ((argv2 >= 0) and (argv2 <= 23)) and ((argv3 >= 0) and (argv3 <= 59)) and ((argv4 >= 0) and (argv4 <= 59))) begin\r
+        move "" to l_01tmpStr\r
+        append l_01tmpStr argv " "  (zeropad(argv2,2)) ":" (zeropad(argv3,2)) ":" (zeropad(argv4,2))\r
+    end\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Returns date or time as a string out of a dateTime struct\r
+function sqldatetime global string argv string argv2 returns string\r
+    local string l_sResult\r
+    \r
+    move (trim(argv)) to argv\r
+    move (trim(uppercase(argv2))) to argv2\r
+    \r
+    if (argv2 = "DATE") begin\r
+        move (mid(argv,2,9)) to l_sResult\r
+        append l_sResult "/" (mid(argv,2,6)) "/" (mid(argv,4,1))\r
+    end\r
+    if (argv2 = "TIME") begin\r
+        move (right(argv,12)) to l_sresult\r
+    end\r
+    \r
+    function_return l_sResult\r
+end_function\r
+\r
+// Returns date or timestamp as a string out of a dateTime struct\r
+function sqltimestampformat global string argv string argv2 returns string\r
+    local string l_sResult\r
+    \r
+    move (trim(argv)) to argv\r
+    move (trim(uppercase(argv2))) to argv2\r
+    \r
+    if (argv2 = "DATE") begin\r
+        move (mid(argv,2,9)) to l_sResult\r
+        append l_sResult "/" (mid(argv,2,6)) "/" (mid(argv,4,1))\r
+    end\r
+    if (argv2 = "TIME") begin\r
+        move (right(argv,length(argv)-pos(" ", argv))) to l_sresult\r
+    end\r
+    \r
+    function_return l_sResult\r
+end_function\r
+\r
+// Returns last day of month as a date\r
+function last_day_of_month global integer month integer year returns date\r
+    local date l_dDate\r
+    if (month = 12) begin\r
+        calc (year+1) to year\r
+        move 1 to month\r
+    end\r
+    else begin\r
+        calc (month+1) to month\r
+    end\r
+    \r
+    move (('01/'+string(month)+'/'+string(year))-1) to l_dDate\r
+    \r
+    function_return l_dDate\r
+end_function\r
+\r
+// Returns a posix timestamp when supplied with a date and numeric values\r
+// for hour, minutes ,seconds and milliseconds: (date,hr,min,sec,millisec)\r
+//\r
+// Also see timestamp_to_posix and posix_to_timestamp in timestamp.inc\r
+function posixtime global date argv number argv2 number argv3 number argv4 number argv5 returns number\r
+    local number l_posix\r
+    \r
+    // Leap seconds not coded\r
+    calc (((integer(argv))-(integer(date("01/01/1970"))))*86400) to l_posix\r
+    calc (((((argv2*60)+argv3)*60)+argv4)+(argv5/1000)+l_posix) to l_posix\r
+    \r
+    function_return l_posix\r
+end_function\r
+\r
+// Returns a comma separated string representing a timestamp (date,hr,min,sec,millisec)\r
+// when supplied with a posix time value.\r
+function posixtime_reverse global number argv returns string\r
+    local date l_date\r
+    local number l_subt \r
+    local integer l_hr l_min l_sec l_msec\r
+    local string l_posix_reverse\r
+    \r
+    // Leap seconds not coded\r
+    calc ((argv/86400)+(integer(date("01/01/1970")))) to l_date\r
+    calc (argv-(((integer(l_date))-(integer(date("01/01/1970"))))*86400)) to l_subt\r
+    calc (l_subt/3600) to l_hr\r
+    calc ((l_subt-(l_hr*3600))/60) to l_min\r
+    calc (l_subt-(((l_hr*60)+l_min)*60)) to l_sec\r
+    calc ((l_subt-((((l_hr*60)+l_min)*60)+l_sec))*1000) to l_msec\r
+            \r
+    move l_date to l_posix_reverse\r
+    append l_posix_reverse "," l_hr "," l_min "," l_sec "," l_msec\r
+   \r
+    function_return l_posix_reverse\r
+end_function\r
+\r
+// Returns 0 until the timeout in seconds value passed is exceeded\r
+// when it returns 1.\r
+//\r
+// Relies on the value of global integer "g_nRuntime_entry";\r
+// the only way to use more than once is to reset that global to 0\r
+// by calling runtime_timeout_reset.\r
+function runtime_timeout global integer argv returns integer\r
+    local integer l_iTimeout\r
+    local number l_nHour l_nMinute l_nSec l_nRuntime_now\r
+    local date l_dToday\r
+    \r
+    sysdate l_dToday l_nHour l_nMinute l_nSec\r
+    move 0 to l_iTimeout\r
+    \r
+    if (argv <> 0) begin\r
+        if (g_nRuntime_entry = 0) begin\r
+            move (posixTime(l_dToday,l_nHour,l_nMinute,l_nSec,0)) to g_nRuntime_entry\r
+        end\r
+    \r
+        move (posixTime(l_dToday,l_nHour,l_nMinute,l_nSec,0)) to l_nRuntime_now\r
+        \r
+        if ((l_nRuntime_now - g_nRuntime_entry) > argv) begin\r
+            move 1 to l_iTimeout\r
+        end\r
+    end\r
+    \r
+    function_return l_iTimeout\r
+end_function \r
+\r
+// Resets the value of global integer "g_nRuntime_entry" as used by\r
+// runtime_timeout\r
+function runtime_timeout_reset global returns integer\r
+    move 0 to g_nRuntime_entry\r
+    function_return 0\r
+end_function \r
+\r
+// Returns the time left in seconsd until runtime_timeout is exceeded.\r
+function runtime_timeout_left global returns integer\r
+    local number l_nHour l_nMinute l_nSec l_nRuntime_now\r
+    local date l_dToday\r
+\r
+    sysdate l_dToday l_nHour l_nMinute l_nSec\r
+    move (posixTime(l_dToday,l_nHour,l_nMinute,l_nSec,0)) to l_nRuntime_now     \r
+    \r
+    function_return (l_nRuntime_now - g_nRuntime_entry)\r
+end_function \r
diff --git a/src/df32/depmacro.inc b/src/df32/depmacro.inc
new file mode 100644 (file)
index 0000000..112a6fa
--- /dev/null
@@ -0,0 +1,59 @@
+//-------------------------------------------------------------------------\r
+// depmacro.inc\r
+//      This file contains definitions of DataFlex 3.2 Console Mode macro \r
+//      functions that rely on previously defined DataFlex functions.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/depmacro.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Macro commands\r
+//-------------------------------------------------------------------------\r
+\r
+// Create replacement GET_FILE_MOD_TIME - this will replace (leap year) in \r
+// faulty builtin GET_FILE_MOD_TIME command.\r
+// Console mode clients rely on GetTime (win32.inc).\r
+#COMMAND IH_GET_FILE_MOD_TIME R "TO" R\r
+    if (sysconf(sysconf_os_short_name) = 'WIN32CM') begin\r
+        move (get_time(!1,3)) to g_sGetFileModTime\r
+        move (Left(g_sGetFileModTime,10)) to !3\r
+\r
+        #IF (!0 > 3)\r
+            move (mid (g_sGetFileModTime,2,11)) to !4\r
+        #ENDIF\r
+\r
+        #IF (!0 > 4)\r
+            move (mid (g_sGetFileModTime,2,14)) to !5\r
+        #ENDIF\r
+\r
+        #IF (!0 > 5)\r
+            move (mid (g_sGetFileModTime,2,17)) to !6\r
+        #ENDIF\r
+    end // Console mode \r
+    else begin // DOS mode\r
+        !A [] $592  !1 !3\r
+\r
+        #IF (!0 > 3)\r
+          !A [] $593  !4\r
+        #ENDIF\r
+\r
+        #IF (!0 > 4)\r
+          !A [] $594  !5\r
+        #ENDIF\r
+\r
+        #IF (!0 > 5)\r
+          !A [] $595  !6\r
+        #ENDIF\r
+\r
+        // Check& correct year for both modes\r
+        move (check_date_error(!3)) to !3\r
+    end  // DOS mode\r
+\r
+#ENDCOMMAND\r
+\r
+// Replace old get_file_mod_time with new\r
+#REPLACE GET_FILE_MOD_TIME IH_GET_FILE_MOD_TIME\r
diff --git a/src/df32/df32func.inc.autodoc b/src/df32/df32func.inc.autodoc
new file mode 100644 (file)
index 0000000..2936ec1
--- /dev/null
@@ -0,0 +1,227 @@
+df32func.inc last compiled on 09/04/2009 at 21:45:13.05 \r
+df32func DLL functions: \r
+tcpcomm.h:external_function ClientSocket "ClientSocket" df32func.dll dword port string host returns integer\r
+tcpcomm.h:external_function ServerSocket "ServerSocket" df32func.dll dword port returns integer\r
+tcpcomm.h:external_function AcceptClient "AcceptClient" df32func.dll returns integer\r
+tcpcomm.h:external_function Send "Send" df32func.dll dword socket string data returns integer\r
+tcpcomm.h:external_function Receive "Receive" df32func.dll dword socket pointer dataOut returns integer\r
+tcpcomm.h:external_function CloseConnection "CloseConnection" df32func.dll dword socket returns integer\r
+tcpcomm.h:external_function PseudoRand "PseudoRand" df32func.dll dword w returns integer\r
+tcpcomm.h:external_function RdtscRand "RdtscRand" df32func.dll returns integer\r
+win32.h:external_function GetDateFormat "GetDateFormatA" kernel32.dll dword LCID dword dwFlags pointer lpsSystemTime pointer lpFormat pointer lpDateStr integer cchDate returns integer\r
+win32.h:external_function GetTimeFormat "GetTimeFormatA" kernel32.dll dword LCID dword dwFlags pointer lpsSystemTime pointer lpFormat pointer lpTimeStr integer cchTime returns integer\r
+win32.h:external_function GetFileTime "GetFileTime" kernel32.dll handle hFileHandle pointer lpCreationTime pointer lpLastAccessTime pointer lpLastWriteTime returns integer\r
+win32.h:external_function FileTimeToSystemTime "FileTimeToSystemTime" kernel32.dll pointer lpFileTime Pointer lpSystemTime returns integer\r
+win32.h:external_function FileTimeToLocalFileTime "FileTimeToLocalFileTime" kernel32.dll pointer lpFileTime Pointer lpSystemTime returns integer\r
+win32.h:external_function FindFirstFile "FindFirstFileA" kernel32.dll pointer lpFileName pointer lpFindFileData returns handle\r
+win32.h:external_function FindNextFile "FindNextFileA" kernel32.dll handle hFindFile pointer lpFindFileData returns integer\r
+win32.h:external_function FindClose "FindClose" kernel32.dll handle hFindFile returns integer\r
+win32.h:external_function LockFile "LockFile" kernel32.dll handle hFile dword dwFileOffsetLow dword dwFileOffsetHigh dword nNumberOfBytesToLockLow dword nNumberOfBytesToLockHigh returns integer\r
+win32.h:external_function UnlockFile "UnlockFile" kernel32.dll handle hFile dword dwFileOffsetLow dword dwFileOffsetHigh dword nNumberOfBytesToLockLow dword nNumberOfBytesToLockHigh returns integer\r
+win32.h:external_function SHFileOperation "SHFileOperationA" shell32.dll pointer lpFileOp returns integer\r
+win32.h:external_function32 GetTempPath "GetTempPathA" kernel32.dll integer nBufferLength pointer lpBuffer_ptr returns integer\r
+win32.h:external_function GetSystemDirectory "GetSystemDirectoryA" kernel32.dll pointer lpBuffer integer uSize returns integer\r
+win32.h:external_function32 mciSendString "mciSendStringA" winmm.dll pointer lpstrCommand pointer lpstrReturnString integer uReturnLength integer hwndCallback returns integer\r
+win32.h:external_function ExitProcessEx  "ExitProcess" Kernel32.dll integer iExitCode returns integer\r
+win32.h:external_function GetComputername "GetComputerNameA" kernel32.dll pointer sBuffer pointer lSize returns integer\r
+win32.h:external_function WNetGetUser "WNetGetUserA" MPR.dll pointer lpName pointer lpUserName string  lpnLength returns DWord\r
+win32.h:external_function SHBrowseForFolder "SHBrowseForFolder" shell32.dll pointer lpsBrowseInfo returns dword\r
+win32.h:external_function SHGetPathFromIDList "SHGetPathFromIDList" shell32.dll pointer pidList pointer lpBuffer returns dWord\r
+win32.h:external_function CoTaskMemFree "CoTaskMemFree" ole32.dll pointer pV returns integer\r
+win32.h:external_function GetPID "_getpid" msvcrt.dll returns integer\r
+win32.h:external_function getShortPathName "GetShortPathNameA" kernel32.dll pointer lpszLongPath pointer lpszShortPath integer cchBuffer returns integer\r
+win32.h:external_function SetConsoleTitle "SetConsoleTitleA" Kernel32.dll string lpszTitle returns integer\r
+win32.h:external_function FindWindow "FindWindowA" user32.dll pointer lpszClassName string lpszWindowName returns handle\r
+win32.h:external_function GetSystemMenu "GetSystemMenu" user32.dll handle hwnd dword bRevert returns dword\r
+win32.h:external_function EnableMenuItem "EnableMenuItem" user32.dll handle hmenu integer uIDEnableItem integer uEnable returns integer\r
+win32.h:external_function ShellExecute "ShellExecuteA" shell32.dll handle hWnd pointer lpOperation pointer lpFile pointer lpParameters pointer lpDirectory integer nShowCmd returns integer\r
+win32.h:external_function CreateProcess "CreateProcessA" kernel32.dll pointer lpAN pointer lpCL pointer lpPA pointer lpTA integer bIH dword dwCF pointer lpE pointer lpCD pointer lpSI pointer lpPi returns integer\r
+win32.h:external_function OpenProcess "OpenProcess" kernel32.dll dword dwDesiredAccessas integer bInheritHandle dword dwProcId returns handle\r
+win32.h:external_function TerminateProcess "TerminateProcess" kernel32.dll handle hProcess integer uExitCode returns integer\r
+win32.h:external_function CloseHandle "CloseHandle" kernel32.dll handle hObject returns integer\r
+win32.h:external_function WaitForSingleObject "WaitForSingleObject" kernel32.dll handle hHandle dword dwMilliseconds returns integer\r
+win32.h:external_function32 Message_Beep "MessageBeep" user32.dll integer iSound returns integer\r
+win32.h:external_function32 ExitWindowsEx "ExitWindowsEx" user32.dll integer uFlags integer dwReserved returns integer\r
+win32.h:external_function lOpen "_lopen" kernel32.dll string lpPathName integer iReadWrite returns integer\r
+win32.h:external_function lClose "_lclose" kernel32.dll handle hFile returns integer\r
+win32.h:external_function GetLastError "GetLastError" kernel32.dll returns integer\r
+win32.h:external_function CreateFile "CreateFileA" kernel32.dll pointer lpFNname dword dwDAccess dword dwSMode pointer lpSecAttrib dword dwCreationDisp dword dwFlagsAndAttrib handle hTemplateFile returns handle\r
+win32.h:external_function GetFileSize "GetFileSize" kernel32.dll handle hFile pointer lpFileSizeHigh returns integer\r
+win32.h:external_function SetFilePointer "SetFilePointer" kernel32.dll handle hFile dword lDistanceToMove pointer lpDistanceToMoveHigh dword dwMoveMethod returns handle\r
+win32.h:external_function ReadFile "ReadFile" kernel32.dll handle hFile pointer lpBuffer integer nNumberOfBytesToRead pointer lpNumberOfBytesRead pointer lpOverlapped returns integer\r
+win32.h:external_function CopyMemory "RtlMoveMemory" kernel32.dll pointer pDst pointer pSrc integer byteLen returns integer\r
+win32.h:external_function EnumProcesses "EnumProcesses" psapi.dll pointer lpidProcess integer cb pointer cbNeeded returns integer\r
+win32.h:external_function EnumProcessModules "EnumProcessModules" psapi.dll  handle hProcess pointer lphModule integer cb integer cbNeeded returns integer\r
+win32.h:external_function WideCharToMultiByte "WideCharToMultiByte" kernel32.dll integer cp dword dwF pointer lpWCS integer cchWC pointer lpMBS integer cchMB string dC string uDC returns integer\r
+win32.h:external_function GetSystemTime "GetSystemTime" kernel32.dll Pointer lpGST returns VOID_TYPE\r
+win32.h:external_function GetTickCount "GetTickCount" kernel32.dll returns dWord\r
+win32.h:external_function32 CoCreateGuid "CoCreateGuid" ole32.dll pointer pGUIDStructure returns word\r
+win32.h:external_function32 StringFromGUID2 "StringFromGUID2" ole32.dll pointer pGUIDStructure pointer lpstrClsId integer cbMax returns dword\r
+win32.h:external_function MsiQueryProductState "MsiQueryProductStateA" msi.dll string szProduct returns integer\r
+win32.h:external_function MilliSleep "Sleep" kernel32.dll integer dwMilliseconds returns integer\r
+win32.h:external_function SetLastError "SetLastError" kernel32.dll dword dwErrCode returns integer\r
+win32.h:external_function FormatMessage "FormatMessageA" kernel32.dll integer dwFlags pointer lpSource dword dwMessageId dword dwLanguageId pointer lpBuffer integer nSize dword Arguments returns integer\r
+win32.h:external_function GetProcessMemoryInfo "GetProcessMemoryInfo" PSAPI.DLL dword l_hProcess pointer ppsmemCounters dword cb returns integer\r
+win32.h:external_function MultiByteToWideChar "MultiByteToWideChar" kernel32.dll integer cp dword dwF pointer lpWCS integer cchWC pointer lpMBS integer cchMB string dC string uDC returns integer\r
+win32.h:external_function GetDiskFreeSpace "GetDiskFreeSpaceA" kernel32.dll string lpRootPathName pointer lpSectorsPC pointer lpBytesPS pointer lpNumberOfFreeClusters pointer lpTotalNOC returns integer\r
+win32.h:external_function InternetCanonicalizeUrl "InternetCanonicalizeUrlA" wininet.dll pointer lpszUrl pointer lpszBuffer pointer lpdwBufferLength dword dwFlags returns integer\r
+win32.h:external_function CryptAcquireContext "CryptAcquireContextA" advapi32.dll pointer phProv string pszContainer string pszProvider dword dwProvType dword dwFlags returns integer\r
+win32.h:external_function CryptReleaseContext "CryptReleaseContext" advapi32.dll pointer phProv dword dwFlags returns integer\r
+win32.h:external_function CryptCreateHash "CryptCreateHash" advapi32.dll handle hProv dword Algid handle hKey dword dwFlags pointer phHash returns integer\r
+win32.h:external_function CryptDestroyHash "CryptDestroyHash" advapi32.dll handle hHash returns integer\r
+win32.h:external_function CryptHashData "CryptHashData" advapi32.dll handle hHash pointer pbData dword dwDataLen dword dwFlags returns integer\r
+win32.h:external_function CryptGetHashParam "CryptGetHashParam" advapi32.dll handle hHash dword dwParam pointer pbData pointer pdwDataLen dword dwFlags returns integer\r
+win32.h:external_function CryptEnumProviders "CryptEnumProvidersA" advapi32.dll dword dwIndex pointer pdwReserved dword dwFlags pointer pdwProvType pointer pcbProvName pointer pszProvName returns integer\r
+win32.h:external_function CryptBinaryToString "CryptBinaryToStringA" crypt32.dll dword pbBinary dword cbBinary dword dwFlags pointer pszString pointer pcchString returns integer\r
+win32.h:external_function CryptGetProvParam "CryptGetProvParam" advapi32.dll handle hProv dword dwParam pointer pbData pointer pdwDataLen dword dwFlags returns integer\r
+win32.h:external_function CryptContextAddRef "CryptGetProvParam" advapi32.dll handle hProv dword pdwReserved dword dwFlags returns integer\r
+win32.h:external_function CryptImportKey "CryptImportKey" advapi32.dll handle hProv pointer pbData pointer pdwDataLen dword hPubKey dword dwFlags pointer phKey returns integer\r
+win32.h:external_function CryptExportKey "CryptExportKey" advapi32.dll handle hKey handle hExpKey dword dwBlobType dword dwFlags pointer pbData pointer pdwDataLen returns integer\r
+win32.h:external_function CryptDeriveKey "CryptDeriveKey" advapi32.dll handle hProv dword Algid handle hHash dword dwFlags pointer phKey returns integer\r
+win32.h:external_function CryptDestroyKey "CryptDestroyKey" advapi32.dll handle hKey returns integer\r
+win32.h:external_function CryptEncrypt "CryptEncrypt" advapi32.dll handle hKey handle hHash dword bFinal dword dwFlags pointer pbData pointer pdwDataLen dword dwBufLen returns integer\r
+win32.h:external_function CryptDecrypt "CryptDecrypt" advapi32.dll handle hKey handle hHash dword bFinal dword dwFlags pointer pbData pointer pdwDataLen returns integer\r
+win32.h:external_function CryptSetKeyParam "CryptSetKeyParam" advapi32.dll handle hKey dword dwParam pointer pbData dword dwFlags returns integer\r
+win32.h:external_function CryptBinaryToString "CryptBinaryToStringA" crypt32.dll dword pbBinary dword cbBinary dword dwFlags pointer pszString pointer pcchString returns integer\r
+win32.h:external_function CryptStringToBinary "CryptStringToBinaryA" crypt32.dll pointer pszString dword cchString dword dwFlags pointer pbBinary pointer pcbBinary pointer pdwSkip pointer pdwFlags returns integer\r
+win32.h:external_function GetVersionEx "GetVersionExA" kernel32.dll pointer lpVersionInfo returns integer\r
+win32.h:external_function GetSystemTime "GetSystemTime" kernel32.dll pointer lpSystemTime returns integer\r
+win32.h:external_function GetTimeZoneInformation "GetTimeZoneInformation" kernel32.dll pointer lpTimeZoneInformation returns integer\r
+win32.h:external_function GetTzi "GetTzi" timezone.dll pointer lpTimeZone pointer lpResult returns integer\r
+df32func functions: \r
+console.inc:function set_mode global integer argv returns integer\r
+console.inc:function screen_display global string argv returns integer\r
+console.inc:function draw_bigchar global string argv integer posx integer posy returns integer\r
+console.inc:function big_text global string argv integer posx integer posy returns integer\r
+date.inc:function get_day_score global date argv returns integer\r
+date.inc:function get_day global date argv returns string\r
+date.inc:function get_month global date argv returns string\r
+date.inc:function get_day_of global date argv returns string\r
+date.inc:function fulldate global date argv returns string\r
+date.inc:function shortdate global date argv returns string\r
+date.inc:function now global string argv returns string\r
+date.inc:function rssdate global date argv string argv2 returns string\r
+date.inc:function cymd global date argv returns string\r
+date.inc:function sqldate global date argv returns string\r
+date.inc:function sqltimestamp global date argv integer argv2 integer argv3 integer argv4 returns string\r
+date.inc:function dftimestamp global date argv integer argv2 integer argv3 integer argv4 returns string\r
+date.inc:function sqldatetime global string argv string argv2 returns string\r
+date.inc:function sqltimestampformat global string argv string argv2 returns string\r
+date.inc:function last_day_of_month global integer month integer year returns date\r
+date.inc:function posixtime global date argv number argv2 number argv3 number argv4 number argv5 returns number\r
+date.inc:function posixtime_reverse global number argv returns string\r
+date.inc:function runtime_timeout global integer argv returns integer\r
+date.inc:function runtime_timeout_reset global returns integer\r
+date.inc:function runtime_timeout_left global returns integer\r
+encode.inc:function is_base64 global integer c returns integer\r
+encode.inc:function int_encode64 global integer uc returns integer\r
+encode.inc:function int_decode64 global integer c returns integer\r
+encode.inc:function encode64 global string sText returns string\r
+encode.inc:function decode64 global string sText returns string\r
+encode.inc:function rc4_array_value integer iIndex returns integer\r
+encode.inc:function rc4 global string key string text returns string\r
+encode.inc:function rc4encode global string key string text returns string\r
+encode.inc:function rc4decode global string key string text returns string\r
+encode.inc:function rc4encode_base64 global string key string text returns string\r
+encode.inc:function rc4decode_base64 global string key string text returns string\r
+hash.inc:function hash_for_df_arrays global string argv returns integer\r
+hash.inc:function reduce_hash global integer argv returns integer\r
+hash.inc:function hash_djb2 global string argv returns integer\r
+hash.inc:function hash_sdbm global string argv returns integer\r
+hash.inc:function hash_lazy global string argv returns integer\r
+math.inc:function decround global number argv integer argv2 returns string\r
+math.inc:function rshift global integer argv integer shift_by returns integer\r
+math.inc:function lshift global integer argv integer shift_by returns integer\r
+math.inc:function ternary global string argv string argv2 string argv3 returns string\r
+string.inc:function titlecase global string argv returns string\r
+string.inc:function replaceall global string argv string argv2 string argv3 returns string\r
+string.inc:function zeropad global string argv integer argv2 returns string\r
+string.inc:function leftpad global string argv integer argv2 returns string\r
+string.inc:function reverse global string argv returns string\r
+string.inc:function addslashes global string argv returns string\r
+string.inc:function quotecsv global string argv returns string\r
+string.inc:function sanitize_int global integer l_iInput integer bound returns integer\r
+string.inc:function sanitize_num global number l_nInput returns integer\r
+string.inc:function sanitize_str global string l_sInput string l_sLevel returns string\r
+string.inc:function nbstring global string argv string argv2 returns string\r
+string.inc:function msxsl global string engine string source string stylesheet string params string outfile returns string\r
+tstamp.inc:function timestemp_to_posix global string inTs returns number\r
+tstamp.inc:function posix_to_timestamp global number argv returns string\r
+tstamp.inc:function timestamp_adjust global string inTs number inMSeconds returns string\r
+tstamp.inc:function interval_to_posix global string argv returns number\r
+tstamp.inc:function timestamp_adjust_interval global string inTs string inInterval returns string\r
+tstamp.inc:function get_day_of_month_for_daylight_savings global integer inYear integer inMonth integer inDayOfWeek integer inDay returns integer\r
+tstamp.inc:function systemtime_utc global returns string\r
+tstamp.inc:function get_bias global string inDestTz integer inYear integer inMon integer inDay integer inHr integer inMin integer inSec integer inIsUTC returns integer\r
+tstamp.inc:function get_utc_time_from_timezone_time global string inDestTz string inTs returns string\r
+tstamp.inc:function get_timezone_time_from_utc_time global string inDestTz string inTs returns string\r
+tstamp.inc:function get_timezone_time_from_timezone_time global string inSourceTz string inDestTz string inTs returns string\r
+win32.inc:function convert_date_format global dword dwLowDateTime dword dwHighDateTime returns string\r
+win32.inc:function list_directory global string argv returns string\r
+win32.inc:function sort_results global integer argv integer argv2 returns integer\r
+win32.inc:function fileopp global string argv string argv2 string argv3 returns integer\r
+win32.inc:function get_local_temp global integer argv returns string\r
+win32.inc:function get_local_system global integer argv returns string\r
+win32.inc:function cd_tray global integer argv returns integer\r
+win32.inc:function exit_process global integer iReturnCode returns integer\r
+win32.inc:function get_process_id global integer argv returns integer\r
+win32.inc:function get_computer global integer argv returns string\r
+win32.inc:function get_user_name global integer argv returns string\r
+win32.inc:function folder_browse global string argv returns String\r
+win32.inc:function get_short_path global string argv returns string\r
+win32.inc:function disable_close global integer argv returns integer\r
+win32.inc:function shell_exec global string argv string argv2 string argv3 returns integer\r
+win32.inc:function create_proc global string argv integer argv2 integer argv3 integer argv4 returns string\r
+win32.inc:function term_proc global string argv integer argv2 returns integer\r
+win32.inc:function is_locked global string argv returns integer\r
+win32.inc:function does_exist global string argv returns integer\r
+win32.inc:function buffer_text_file global string argv string argv2 returns integer\r
+win32.inc:function file_size_bytes global string argv returns integer\r
+win32.inc:function to_ascii global string argv returns string\r
+win32.inc:function to_unicode global string argv returns string\r
+win32.inc:function to_utf8 global string argv returns string\r
+win32.inc:function get_procs global integer argv returns integer\r
+win32.inc:function time_data global integer argv returns string\r
+win32.inc:function fill_0 global integer iValue integer iSize returns string\r
+win32.inc:function check_date_error global string sDate returns date\r
+win32.inc:function get_time global string sFileName integer iMode returns string\r
+win32.inc:function create_guid global returns string        \r
+win32.inc:function get_last_error_detail global integer iError returns string\r
+win32.inc:function disk_info global string argv string argv2 returns number\r
+win32.inc:function get_mem_usage global returns integer\r
+win32.inc:function urldecode global string argv returns string\r
+win32.inc:function urlencode global string argv returns string\r
+win32.inc:function get_os_version global returns string\r
+win32.inc:function get_os_version_numeric global returns number\r
+win32.inc:function binary_to_string_to_binary global string argv string argv2 string argv3 returns string\r
+win32.inc:function binary_to_string global string argv string argv2 returns string\r
+win32.inc:function string_to_binary global string argv string argv2 returns string\r
+win32.inc:function ms_adv_listproviders global returns integer\r
+win32.inc:function msAdvCrypt_hash global string in_data string in_hash returns string\r
+win32.inc:function sha512_hex global string in_data returns string\r
+win32.inc:function sha512_base64 global string in_data returns string\r
+win32.inc:function sha384_hex global string in_data returns string\r
+win32.inc:function sha384_base64 global string in_data returns string\r
+win32.inc:function sha256_hex global string in_data returns string\r
+win32.inc:function sha256_base64 global string in_data returns string\r
+win32.inc:function sha1_hex global string in_data returns string\r
+win32.inc:function sha1_base64 global string in_data returns string\r
+win32.inc:function md5_hex global string in_data returns string\r
+win32.inc:function md5_base64 global string in_data returns string\r
+win32.inc:function aes256_hex_enc global string in_data string in_key returns string\r
+win32.inc:function aes256_hex_dec global string in_data string in_key returns string\r
+df32func procedures: \r
+encode.inc:procedure set rc4_array_value integer iIndex integer iVal\r
+encode.inc:procedure create_rc4_key string key\r
+df32func classes: \r
+data.inc:class linkedlist is an array\r
+data.inc:class hashtable is an array\r
+data.inc:class hash is an array\r
+data.inc:class matrix is an array\r
+data.inc:class rss20 is a matrix\r
+data.inc:class filelist is a matrix\r
+data.inc:class UnicodeReader is an array\r
+data.inc:class ListDirectory is a matrix\r
+data.inc:class ProcessList is an array\r
+string.inc:class StringTokenizer is an array\r
+win32.inc:class msAdvCrypt is an array\r
diff --git a/src/df32/df32func.mk b/src/df32/df32func.mk
new file mode 100644 (file)
index 0000000..9ebc725
--- /dev/null
@@ -0,0 +1,104 @@
+//-------------------------------------------------------------------------\r
+// df32func.mk\r
+//             Primary source file for DateFlex 3.2 Console Mode "df32func" extentions\r
+//\r
+// This is the file to be compiled by the dfcomp command\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/df32func.mk\r
+//-------------------------------------------------------------------------\r
+//#NOISY 99\r
+//#NOISY 1\r
+\r
+#REM ----------------------------------------------------------------------\r
+#REM Compiling df32func.inc\r
+#REM If precompiling ensure df32func.flp is with your \r
+#REM bytecode and df32func.pki is with your packages\r
+#REM ----------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Set dataflex epoch and set date format to 4 digit years\r
+//-------------------------------------------------------------------------\r
+\r
+set_date_attribute date4_state to dftrue\r
+set_date_attribute epoch_value to 80\r
+set_date_attribute sysdate4_state to dftrue\r
+\r
+//-------------------------------------------------------------------------\r
+// Standard DF32 Console Mode packages \r
+//-------------------------------------------------------------------------\r
+\r
+Use CASE                                        //this package allows the use of switch statements in DataFlex\r
+Use UI                                          //this package contains all the user interface / data classes for OO DataFlex\r
+Use MONARRAY                                    //this package allows the easy monitoring of an array\r
+Use TIMER                                       //this package allows the use of timers to control events\r
+Use DLL                                         //this package allows import of dynamic link libraries, N.B. It contains fake\r
+                                                //WORD and BYTE types that are incorrect for use in C struct types\r
+//-------------------------------------------------------------------------\r
+// Defines used to control some compile time behaviour\r
+//-------------------------------------------------------------------------\r
+\r
+//Define enable_dfassert\r
+Define no_backslash_quote\r
+Define default_file_channel                                            for 9\r
+\r
+//-------------------------------------------------------------------------\r
+// Global variables used to control some runtime behaviour\r
+//-------------------------------------------------------------------------\r
+\r
+// Turn on any debug lines at runtime\r
+indicator show_debug_lines\r
+\r
+//Used by set msxsl function (string.inc) - set to true to keep msxsl binary in one particular place\r
+indicator g_bMsxslPresent                       \r
+string g_sMsxslEngine\r
+\r
+//used by runtime (date.inc)\r
+integer g_nRuntime_entry \r
+\r
+//used by replacement GET_FILE_MOD_TIME command (depmacro.inc)                     \r
+string  g_sGetfileModTime\r
+\r
+indicate g_bMsxslPresent false                  \r
+move "c:\msxsl.exe" to g_sMsxslEngine\r
+move 0 to g_nRuntime_entry\r
+indicate show_debug_lines false\r
+\r
+\r
+//-------------------------------------------------------------------------\r
+// Include main content\r
+//-------------------------------------------------------------------------\r
+\r
+//Including header file win32.h\r
+#INCLUDE win32.h\r
+//Including include file tcpcom.h\r
+#INCLUDE tcpcomm.h\r
+//Including include file console.h\r
+#INCLUDE console.h\r
+//Including include file encode.h\r
+#INCLUDE encode.h\r
+//Including include file errors.h\r
+#INCLUDE errors.h\r
+//Including include file macro.inc\r
+#INCLUDE macro.inc\r
+//Including include file math.inc\r
+#INCLUDE math.inc\r
+//Including include file win32.inc\r
+#INCLUDE win32.inc\r
+//Including include file string.inc\r
+#INCLUDE string.inc\r
+//Including include file date.inc\r
+#INCLUDE date.inc\r
+//Including include file console.inc\r
+#INCLUDE hash.inc\r
+//Including include file data.inc\r
+#INCLUDE data.inc\r
+//Including include file depmacro.inc\r
+#INCLUDE console.inc\r
+//Including include file hash.inc\r
+#INCLUDE depmacro.inc\r
+//Including include file tstamp.inc\r
+#INCLUDE tstamp.inc\r
+//Including include file encode.inc\r
+#INCLUDE encode.inc\r
diff --git a/src/df32/encode.h b/src/df32/encode.h
new file mode 100644 (file)
index 0000000..9d9eb56
--- /dev/null
@@ -0,0 +1,19 @@
+//-------------------------------------------------------------------------
+// encode.h
+//      This file contains soem globale used by RC4 encoding functions
+//
+// This file is to be included when using RC4/Base64 encoding in df32func.mk
+//
+// Copyright (c) 2006-2009, glyn@8kb.co.uk
+// 
+// df32func/encode.h
+//-------------------------------------------------------------------------
+
+Define __encode_h__
+
+//-------------------------------------------------------------------------
+// Global variables
+//-------------------------------------------------------------------------            
+
+// Used by RC4 functions
+string RC4SBXA 128 RC4SBXB 128  RC4SBXA_TMP 128 RC4SBXB_TMP 128     
diff --git a/src/df32/encode.inc b/src/df32/encode.inc
new file mode 100644 (file)
index 0000000..2bf83a8
--- /dev/null
@@ -0,0 +1,227 @@
+//-------------------------------------------------------------------------\r
+// encode.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to provide base64 and rc4 encoding/decoding.  More advanced \r
+//      encoding and encryption can be found in win32.inc.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) ????, ????@????.?? (unknown origin)\r
+// \r
+// df32func/encode.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Check if a string is base64\r
+function is_base64 global integer c returns integer\r
+    if (c >= ascii('A') and c <= ascii('Z')) function_return true\r
+    else if (c >= ascii('a') and c <= ascii('z')) function_return true\r
+    else if (c >= ascii('0') and c <= ascii('9')) function_return true\r
+    else if (c = ascii('+')) function_return true\r
+    else if (c = ascii('/')) function_return true\r
+    else if (c = ascii('=')) function_return true\r
+    else function_return false\r
+end_function\r
+\r
+//encode integer to hex ascii code\r
+function int_encode64 global integer uc returns integer\r
+    if (uc < 26) function_return (ascii('A')+uc)\r
+    else if (uc < 52) function_return (ascii('a')+(uc-26))\r
+    else if (uc < 62) function_return (ascii('0')+(uc-52))\r
+    else if (uc = 62) function_return (ascii('+'))\r
+    else function_return (ascii('/'))\r
+end_function\r
+\r
+//decode hex to integer ascii code\r
+function int_decode64 global integer c returns integer\r
+    if (c >= ascii('A') and c <= ascii('Z')) function_return (c - ascii('A'))\r
+    else if (c >= ascii('a') and c <= ascii('z')) function_return (c - ascii('a') + 26)\r
+    else if (c >= ascii('0') and c <= ascii('9')) function_return (c - ascii('0') + 52)\r
+    else if (c = ascii('+')) function_return 62\r
+    else function_return 63\r
+end_function\r
+\r
+// encode to base64\r
+function encode64 global string sText returns string\r
+    local integer iLen iPos iChar\r
+    local integer by1 by2 by3 \r
+    local integer by4 by5 by6 by7\r
+    local string  sRet\r
+    \r
+    move (length(sText)) to iLen\r
+    move 1 to iPos\r
+    \r
+    if iPos Lt 1 function_return \r
+    \r
+    while (iPos <= iLen)            \r
+       move 0 to by1\r
+       move 0 to by2\r
+       move 0 to by3       \r
+       move 0 to by4\r
+       move 0 to by5\r
+       move 0 to by6\r
+       move 0 to by7\r
+       \r
+       if (iPos+0 <= iLen) move (ascii(mid(sText,1,iPos+0))) to by1 \r
+       if (iPos+1 <= iLen) move (ascii(mid(sText,1,iPos+1))) to by2\r
+       if (iPos+2 <= iLen) move (ascii(mid(sText,1,iPos+2))) to by3       \r
+       move (rshift(by1,2)) to by4\r
+       move (lshift((by1 iand 3),4)  ior rshift(by2,4)) to by5  \r
+       move (lshift((by2 iand 15),2) ior rshift(by3,6)) to by6 \r
+       move (by3 iand 63) to by7\r
+       \r
+       append sRet (character(int_encode64(by4)))\r
+       append sRet (character(int_encode64(by5)))\r
+       \r
+       if (iPos+1<=iLen) append sRet (character(int_encode64(by6)))\r
+       else append sRet "=" \r
+       \r
+       if (iPos+2<=iLen) append sRet (character(int_encode64(by7)))  \r
+       else append sRet "="\r
+       \r
+       move (iPos+3) to iPos\r
+    end\r
+    function_return sRet\r
+end_function\r
+\r
+// decode from base64\r
+function decode64 global string sText returns string\r
+    local integer iLen iPos iChar isOK\r
+    local integer c1  c2  c3  c4 \r
+    local integer cc1 cc2 cc3\r
+    local integer by1 by2 by3 by4\r
+    local string  sRet\r
+    \r
+    move (length(sText)) to iLen\r
+    \r
+    move 1 to isOK\r
+    for iPos from 1 to iLen\r
+       move (is_base64(ascii(mid(sText,1,iPos)))) to isOK \r
+       if isOK eq 0 Break\r
+    loop\r
+\r
+    if (isOK) begin\r
+      move 1 to iPos\r
+      while (iPos<=iLen)\r
+        move (ascii('A')) to c1\r
+        move (ascii('A')) to c2\r
+        move (ascii('A')) to c3\r
+        move (ascii('A')) to c4\r
+       \r
+        if (iPos+0<=iLen) move (ascii(mid(sText,1,iPos+0))) to c1 \r
+        if (iPos+1<=iLen) move (ascii(mid(sText,1,iPos+1))) to c2\r
+        if (iPos+2<=iLen) move (ascii(mid(sText,1,iPos+2))) to c3\r
+        if (iPos+3<=iLen) move (ascii(mid(sText,1,iPos+3))) to c4\r
+       \r
+        move (int_decode64(c1)) to by1\r
+        move (int_decode64(c2)) to by2\r
+        move (int_decode64(c3)) to by3\r
+        move (int_decode64(c4)) to by4\r
+       \r
+        append sRet (character(lshift(by1,2) ior rshift(by2,4)))\r
+        if (c3<>ascii('=')) append sRet (character(lshift((by2 iand 15),4) ior rshift(by3,2)))\r
+        if (c4<>ascii('=')) append sRet (character(lshift((by3 iand 3) ,6) ior by4))\r
+                                                                          \r
+        move (iPos+4) to iPos\r
+      end\r
+    end\r
+    function_return sRet\r
+end_function\r
+\r
+procedure set rc4_array_value integer iIndex integer iVal\r
+    move (iIndex+1)  to iIndex\r
+    if iIndex Le 128 ;\r
+         move (Overstrike(character(iVal),rc4SBXA,iIndex))     to rc4SBXA\r
+    else move (Overstrike(character(iVal),rc4SBXB,iIndex-128)) to rc4SBXB\r
+end_procedure\r
+\r
+function rc4_array_value integer iIndex returns integer\r
+    local integer iRet\r
+    move (iIndex+1)  to iIndex\r
+    if iIndex Le 128 ;\r
+         move (ascii(mid(rc4SBXA,1,iIndex)))     to iRet\r
+    else move (ascii(mid(rc4SBXB,1,iIndex-128))) to iRet\r
+    function_return iRet\r
+end_function\r
+\r
+procedure create_rc4_key string key\r
+    local integer a b keylen idx\r
+    local integer ikey atmp btmp\r
+\r
+    move (length(key)) to keylen\r
+    \r
+    // initialise key array\r
+    move rc4SBXA to rc4SBXA_TMP\r
+    move rc4SBXA to rc4SBXB_TMP\r
+    \r
+    move "" to rc4SBXA\r
+    move "" to rc4SBXB\r
+    \r
+    for idx from 0 to 255\r
+       set rc4_array_value idx to idx\r
+    loop                   \r
+    \r
+    // encode key array\r
+    for a from 0 to 255\r
+       move (ascii(mid(key,1,mod(a,keylen)+1))) to ikey\r
+       get rc4_array_value a to atmp\r
+       move (mod((b+atmp+ikey),256)) to b\r
+\r
+       get rc4_array_value b to btmp\r
+\r
+       set rc4_array_value a to btmp\r
+       set rc4_array_value b to atmp\r
+    loop\r
+    \r
+end_procedure\r
+\r
+function rc4 global string key string text returns string\r
+    local integer ix iy temp offset origlen cipherlen\r
+    local integer ixtmp iytmp ixytmp ixc\r
+    local string sRet\r
+\r
+    send create_rc4_key key  \r
+    move (length(text)) to origlen\r
+    \r
+    move "" to sRet\r
+    for offset from 1 to origlen\r
+        move (mod((offset-1),256)) to ix\r
+        get rc4_array_value ix to ixtmp\r
+        move (mod((iy+ixtmp),256)) to iy\r
+        //\r
+        get rc4_array_value ix to ixtmp\r
+        get rc4_array_value iy to iytmp\r
+        //\r
+        set rc4_array_value ix to iytmp\r
+        set rc4_array_value iy to ixtmp\r
+        //\r
+        move (ascii(mid(text,1,offset))) to ixc\r
+        //\r
+        get rc4_array_value ix to ixtmp\r
+        get rc4_array_value iy to iytmp\r
+        get rc4_array_value (mod((ixtmp+iytmp),256)) to ixytmp\r
+        move ((ixc ior ixytmp) - (ixc iand ixytmp)) to ixc //XOR\r
+        //\r
+        move (sRet+(character(ixc))) to sRet\r
+    loop\r
+    function_return sRet\r
+end_function\r
+\r
+function rc4encode global string key string text returns string\r
+    function_return (rc4(key,text))\r
+end_function\r
+\r
+function rc4decode global string key string text returns string\r
+    function_return (rc4(key,text))\r
+end_function\r
+\r
+function rc4encode_base64 global string key string text returns string\r
+    function_return (encode64(rc4encode(key,text)))\r
+end_function\r
+\r
+function rc4decode_base64 global string key string text returns string\r
+    function_return (rc4decode(key,decode64(text)))\r
+end_function\r
diff --git a/src/df32/errors.h b/src/df32/errors.h
new file mode 100644 (file)
index 0000000..5c7bb00
--- /dev/null
@@ -0,0 +1,63 @@
+//-------------------------------------------------------------------------
+// errors.h
+//      This file contains pre-defined error messages for df32func logic.
+//
+// This file is to be included in df32func.mk
+//
+// Copyright (c) 2006-2009, glyn@8kb.co.uk
+// 
+// df32func/errors.h
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+// Error codes
+//-------------------------------------------------------------------------
+enum_list
+    Define ERROR_CODE_DUPLICATE_HASH_KEY$ for 8000
+    Define ERROR_CODE_URLDECODE$
+    Define ERROR_CODE_URLENCODE$
+    Define ERROR_CODE_UNKNOWN_ALGORITHM$
+    Define ERROR_CODE_INCOMPATIBLE_ALGORITHM$
+    Define ERROR_CODE_INVALID_BLOCKSIZE$
+    Define ERROR_CODE_UNRECOGNISED_MODE$
+    Define ERROR_CODE_NO_CONTEXT$
+    Define ERROR_CODE_INVALID_ADDRESS$
+    Define ERROR_CODE_ADDRESS_TAKEN$
+    Define ERROR_CODE_UNKNOWN_FORMAT$
+    Define ERROR_CODE_INVALID_TIMESTAMP$
+    Define ERROR_CODE_INVALID_POSIX_NUMBER$
+    Define ERROR_CODE_INVALID_SYSTEM_TIMEZONE$
+    Define ERROR_CODE_INVALID_BOOLEAN$
+end_enum_list
+
+//-------------------------------------------------------------------------
+// Error messages
+//
+// Maxsize = 40 chars   Width guide         |----------------------------------------|
+//-------------------------------------------------------------------------
+
+#REPLACE ERROR_MSG_DUPLICATE_HASH_KEY       "Duplicate key in unique hashed column"
+#REPLACE ERROR_MSG_URLDECODE                "Urldecode failed"
+#REPLACE ERROR_MSG_URLENCODE                "Urlencode failed"
+#REPLACE ERROR_MSG_UNKNOWN_ALGORITHM        "Unknown crypt algorithm: ??"
+#REPLACE ERROR_MSG_INOMPATIBLE_ALGORITHM    "Incompatible algorithm: ??"
+#REPLACE ERROR_MSG_INVALID_BLOCKSIZE        "Invalid blocksize: ??"
+#REPLACE ERROR_MSG_UNRECOGNISED_MODE        "Unrecognised mode: ??"
+#REPLACE ERROR_MSG_NO_CONTEXT               "No crypt context exists"
+#REPLACE ERROR_MSG_INVALID_ADDRESS          "Invalid address: ??"
+#REPLACE ERROR_MSG_ADDRESS_TAKEN            "Address already taken: ??"
+#REPLACE ERROR_MSG_UNKNOWN_FORMAT           "Unknown format: ?? not HEX|BASE64|BIN"
+#REPLACE ERROR_MSG_INVALID_TIMESTAMP        "Invalid timestmap"
+#REPLACE ERROR_MSG_INVALID_POSIX_NUMBER     "Invalid posix number: ??"
+#REPLACE ERROR_MSG_INVALID_SYSTEM_TIMEZONE  "Invalid system timezone"
+#REPLACE ERROR_MSG_INVALID_BOOLEAN          "Value does not evaluate to boolean"
+
+//-------------------------------------------------------------------------
+// Error message detail
+//
+// Maxsize = 32 chars   Width guide         |--------------------------------|
+//-------------------------------------------------------------------------
+#REPLACE ERROR_DETAIL_DUPLICATE_HASH_KEY    "Duplicate key at index: ??"
+#REPLACE ERROR_DETAIL_GETLASTERROR          "GetLastError = ??"
+#REPLACE ERROR_DETAIL_INVALID_TIMESTAMP     "Format: ??"
+#REPLACE ERROR_DETAIL_INVALID_BOOLEAN       "Value ?? != true/false"
diff --git a/src/df32/hash.inc b/src/df32/hash.inc
new file mode 100644 (file)
index 0000000..9b668ea
--- /dev/null
@@ -0,0 +1,126 @@
+//-------------------------------------------------------------------------\r
+// hash.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to provide limited hashing algorithms.  More advanced hashing\r
+//      can be found in win32.inc.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/hash.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Produces an integer hash value for indexing into a DataFlex array.\r
+//\r
+// This is a rather unaccomplished hash, but is specifically designed to produce\r
+// positive hashed values with a relatively low integer range (< 10,000,000)\r
+// in order to give a decent distribution and still fit into a DataFlex 3.2 \r
+// array object.\r
+// It can without doubt be improved.\r
+//\r
+// Note that whilst this hash may appear to preserve ascii order to some \r
+// degree this is an artifact rather than by design and cannot be relied on.\r
+function hash_for_df_arrays global string argv returns integer\r
+    local integer l_iHash\r
+    local string l_sTmp\r
+    \r
+    move 0 to l_iHash\r
+    move (lowercase(trim(argv))) to l_sTmp\r
+    \r
+    if (l_sTmp <> "") begin\r
+        // Start at the first character of the string and produce distributed starting points for integer hash values\r
+        if (mid(l_sTmp,1,1)) in "1234567890" move (((ascii(mid(l_sTmp,1,1)))-47)*200000) to l_iHash                 //index at 1-10\r
+        if (mid(l_sTmp,1,1)) in "abcdefghijklmnopqrstuvwxyz" move (((ascii(mid(l_sTmp,1,1)))-86)*200000) to l_iHash //index at 11-36        \r
+        if not (mid(l_sTmp,1,1)) in "1234567890abcdefghijklmnopqrstuvwxyz" move (37*200000) to l_iHash              //index at 37+\r
+\r
+        // Take the sum of the second, last and middle chars (upper and lowercase) in the string and add to the hash\r
+        if (length(argv) > 1) calc (l_iHash + (ascii(mid(argv,1,2)))) to l_iHash\r
+        if (length(argv) > 2) calc (l_iHash + (ascii(mid(argv,1,(length(argv)))))) to l_iHash\r
+        if (length(argv) > 4) calc (l_iHash + (ascii(mid(argv,1,(length(argv)/2))))) to l_iHash\r
+\r
+        // If the string is longer than 9 chars add the second last val * 100 to the hash\r
+        if (length(argv) > 9) calc (l_iHash + (100*(ascii(mid(argv,1,(length(argv)-2)))))) to l_iHash\r
+\r
+        // Add the length of the string onto the hash if shorter than 255 chars, else add 256.\r
+        if (length(argv) > 255) calc (l_iHash + 256) to l_iHash\r
+        else calc (l_iHash + length(argv)) to l_iHash\r
+    end\r
+    else begin\r
+        move 0 to l_iHash\r
+    end\r
+    \r
+    function_return l_iHash\r
+end_function\r
+\r
+// Chop up an integer hash that is out of the optimal DataFlex 3.2 array\r
+// size range and make it fit. This reduces the uniqueness of the hash but\r
+// unfortuantely is a necessary evil when using out of range hashes.\r
+function reduce_hash global integer argv returns integer\r
+    local integer l_iHash\r
+    \r
+    // Make sure positive\r
+    if (argv < 0) calc (argv*-1) to l_iHash\r
+    else move argv to l_iHash\r
+    \r
+    // Unashamedly chop out the middle range\r
+    if (length(string(l_iHash)) > 7) begin\r
+        move (integer(left(string(l_iHash),3)+right(string(l_iHash), 3))) to l_iHash\r
+    end\r
+        \r
+    function_return l_iHash\r
+end_function\r
+\r
+// Djb2 hashing from Dan Bernstein\r
+//\r
+// The main info is here http://fr.wikipedia.org/wiki/Table_de_hachage#Fonction_de_Hachage\r
+//\r
+// http://en.wikipedia.org/wiki/Daniel_J._Bernstein\r
+// http://cr.yp.to/djb.html\r
+// http://www.cse.yorku.ca/~oz/hash.html\r
+function hash_djb2 global string argv returns integer\r
+    local integer l_iHash l_i\r
+    \r
+    move 5381 to l_iHash\r
+    \r
+    for l_i from 1 to (length(argv))\r
+        move ((LShift(l_iHash,5) + l_iHash) + (ascii(mid(argv,1,L_i)))) to l_iHash\r
+    loop\r
+    \r
+    function_return l_iHash\r
+end_function\r
+\r
+// This is the SDBM hashing algorithm as used in berkeley DB\r
+//\r
+// http://cpansearch.perl.org/src/RGARCIA/perl-5.10.0/ext/SDBM_File/sdbm/README\r
+// http://en.wikipedia.org/wiki/Dbm\r
+// http://en.wikipedia.org/wiki/Sleepycat_Software\r
+// http://en.wikipedia.org/wiki/Berkeley_DB\r
+function hash_sdbm global string argv returns integer\r
+    local integer l_iHash l_i\r
+    \r
+    move 0 to l_iHash\r
+    \r
+    for l_i from 1 to (length(argv))\r
+        move ((ascii(mid(argv,1,L_i))) + (LShift(l_iHash,6)) + (LShift(l_iHash,16)) - l_iHash) to l_iHash\r
+    loop\r
+    \r
+    function_return l_iHash\r
+end_function\r
+\r
+// Lazy hash, efficient for small fairly unique strings.\r
+function hash_lazy global string argv returns integer\r
+    local integer l_iHash l_i\r
+    \r
+    move 0 to l_iHash\r
+    \r
+    for l_i from 1 to (length(argv))\r
+        move (l_iHash + (ascii(mid(argv,1,L_i)))) to l_iHash\r
+    loop\r
+    \r
+    function_return l_iHash\r
+end_function\r
diff --git a/src/df32/macro.inc b/src/df32/macro.inc
new file mode 100644 (file)
index 0000000..9c250a9
--- /dev/null
@@ -0,0 +1,111 @@
+//-------------------------------------------------------------------------
+// macro.inc
+//      This file contains definitions of DataFlex 3.2 Console Mode macro functions
+//      to provide some extended command functionality.
+//
+// This file is to be included in df32func.mk
+//
+// Copyright (c) 2006-2009, glyn@8kb.co.uk
+// 
+// df32func/macro.inc
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+// Macro commands
+//-------------------------------------------------------------------------
+
+
+// Assertions
+// ASSERT <true/false evaluation> <assert message> -- provides a similar functionality to c assert.  
+// 
+//     if enable_dfassert is defined then evaluations are run and errors are raised
+//     if enable_dfassert is undefined then assertions are effectively removed at compile time
+//    
+//     A failed assertion will raise an error
+//
+// Example usage:   
+//    
+//     Define enable_dfassert
+//     ASSERT (1=2) "TEST ASSERT"
+//
+#COMMAND ASSERT R
+    #IFDEF enable_dfassert
+        #IF (!0=2)
+            #IFTYPE !1 "I"
+                if (!1 = 0);
+                    error 999999 ("RAISED ASSERTION: '"+string(!2)+"'")
+            #ENDIF
+        #ENDIF
+    #ENDIF
+#ENDCOMMAND
+
+// Custom errors
+//
+// Used to produce multiline error messages as the error command is 
+// limited to 40 chars (the original length of ERROR_DESCR in FLEXERRS.DAT)
+//
+// Will replace "??" in any message with a variable
+//
+// Example usage:
+//
+//     custom_error <error_code> <error_message>
+//     custom_error <error_code> <error_message> <error_message replacement>
+//     custom_error <error_code> <error_message> <error_detail> <error_detail replacement>
+//
+#COMMAND CUSTOM_ERROR R
+    #IF (!0>1)
+        #IFTYPE !1 "I"
+            #IFTYPE !2 "S"
+                #IF (!0=2)
+                    error !1 !2
+                #ELSE
+                    #IF (!0=3)
+                        error !1 (replace("??", !2, string(!3)))
+                    #ELSE
+                        #IF (!0=4)
+                            error !1 !2
+                            #IFTYPE !3 "S"
+                                error !1 ("Detail: "+(replace("??", !3, string(!4))))
+                            #ENDIF
+                        #ENDIF
+                    #ENDIF
+                #ENDIF
+            #ENDIF
+        #ENDIF
+    #ENDIF        
+#ENDCOMMAND
+
+// Ternary command (an operator would be nice)
+// Behaves similar to perl/c ternary operators E.g. "(evaluation) ? true_var : false_var"
+//
+// Example usage:
+//
+//     ternary mytable.myboolean "YES" "NO" my_string
+//     ternary (1=1) "YES" "NO" my_string
+//
+// Note that this command form functions just like perl/c and if something like:
+// "(evaluation) ? true_evaluation : false_evaluation" is written then only the
+// secondary OR tertiary evaluation will execute dependant on the result of 
+// the primary evaluation.
+//
+// There is also a "ternary" function (math.inc) which can be used in place of an operator, 
+// however beware that the function works differently; both the secondary AND tertiary
+// evaluations happen before primary evaluation is tested, rather than being exclusive
+// (as they should really be) this is a limitation of passing via the function. Thus 
+// the function is only really useful for variables.
+//
+#COMMAND TERNARY R
+    #IF (!0>3)
+        #IFTYPE !1 "I"
+            if (!1 = 1) move !2 to !4
+            else move !3 to !4
+        #ELSE
+            #IFTYPE !1 "S"
+                if ((lowercase(!1) eq 't') or (lowercase(!1) eq 'true')) move !2 to !4
+                else move !3 to !4
+            #ELSE
+                move !3 to !4
+            #ENDIF
+        #ENDIF
+    #ENDIF
+#ENDCOMMAND
diff --git a/src/df32/math.inc b/src/df32/math.inc
new file mode 100644 (file)
index 0000000..98a7ee4
--- /dev/null
@@ -0,0 +1,72 @@
+//-------------------------------------------------------------------------\r
+// math.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to provide extended mathematical capabilities.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/math.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Round a number to n decimal places. Returns a string.\r
+// argv = number argv2 = decimal places\r
+function decround global number argv integer argv2 returns string\r
+    local number l_nInVal l_nDcnVal l_nDcnDecVal l_nDcnAppPoints\r
+    local integer l_iDcnPoints\r
+    local string l_sReturn\r
+\r
+    move argv to l_nInVal\r
+    move argv2 to l_iDcnPoints\r
+  \r
+    move (number("0."+repeat(0,l_iDcnPoints)+"5")) to l_nDcnDecVal\r
+    if (l_nInVal < 0) calc (l_nDcnDecVal*-1) to l_nDcnDecVal\r
+    calc (l_nInVal+l_nDcnDecVal) to l_nDcnVal   \r
+\r
+    move (l_iDcnPoints-(length(l_nDcnVal)-pos(".", l_nDcnVal))) to l_nDcnAppPoints\r
+    if (l_iDcnPoints >= 1) move (left(l_nDcnVal,((pos(".",l_nDcnVal))+l_iDcnPoints))) to l_sReturn\r
+    else move (left(l_nDcnVal,((pos(".",l_nDcnVal))+l_iDcnPoints)-1)) to l_sReturn\r
+    if (not (l_sReturn contains ".") and l_iDcnPoints <> 0) append l_sReturn "." (repeat("0",l_iDcnPoints))\r
+    else if (l_nDcnAppPoints > 0) append l_sReturn (repeat("0",l_nDcnAppPoints))\r
+    if (number(l_sReturn) = 0) move (replaces("-",l_sReturn,"")) to l_sReturn\r
+\r
+    function_return l_sReturn\r
+\r
+end_function\r
+\r
+// Performs a right binary shift on a variable.\r
+// Relies on the embedded binary arithmetic of ior and iand\r
+function rshift global integer argv integer shift_by returns integer\r
+    function_return (integer(argv/(2^shift_by)) iand 255)\r
+end_function\r
+\r
+// Performs a left binary shift on a variable.\r
+// Relies on the embedded binary arithmetic of ior and iand\r
+function lshift global integer argv integer shift_by returns integer\r
+    function_return (integer(argv*(2^shift_by)) iand 255) \r
+end_function\r
+\r
+// Ternary operator function like perls boolean ? "true var" : "false var"\r
+// Relies on TERNARY command (macro.inc) - beware all evaluations passed to \r
+// the function are actually run, so only usefull for strings really in argv2/3\r
+function ternary global string argv string argv2 string argv3 returns string\r
+    local string l_sReturn\r
+    local integer tmp\r
+\r
+    if ((argv = "0") or (argv = "1")) begin\r
+            ternary (integer(argv)) argv2 argv3 l_sReturn\r
+\r
+    end\r
+    else if ("@t@f@false@true@" contains ("@"+lowercase(argv)+"@")) begin\r
+            ternary argv argv2 argv3 l_sReturn\r
+    end\r
+    else begin\r
+            custom_error ERROR_CODE_INVALID_BOOLEAN$ ERROR_MSG_INVALID_BOOLEAN ERROR_DETAIL_INVALID_BOOLEAN argv\r
+    end\r
+    function_return l_sReturn\r
+end_function\r
diff --git a/src/df32/string.inc b/src/df32/string.inc
new file mode 100644 (file)
index 0000000..9607e63
--- /dev/null
@@ -0,0 +1,367 @@
+//-------------------------------------------------------------------------\r
+// string.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      and classes to provide extended string manipulation capabilities.\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/string.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Convert a string to titlecase\r
+function titlecase global string argv returns string\r
+    local string l_01tmpStr\r
+    local integer l_01tmpInt\r
+\r
+    move "" to l_01tmpStr\r
+    lp_maketitle01:\r
+    append l_01tmpStr (uppercase(left(argv,1)))\r
+    pos " " in argv to l_01tmpInt\r
+    if l_01tmpInt eq 0 begin\r
+        length (trim(argv)) to l_01tmpInt\r
+        append l_01tmpStr (lowercase(right(argv,(l_01tmpInt-1))))\r
+        goto lp_exittitle01\r
+    end\r
+    append l_01tmpStr (lowercase(mid(argv,(l_01tmpInt-1),2)))        \r
+    trim (mid(argv,(length(argv)),(l_01tmpInt+1))) to argv        \r
+    goto lp_maketitle01\r
+    lp_exittitle01:\r
+\r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+//replace all characters in argv2 found in argv with srting in argv3 - see replaces\r
+function replaceall global string argv string argv2 string argv3 returns string\r
+    local integer l_01tmpInt\r
+    \r
+    move (trim(argv)) to argv\r
+    for l_01tmpInt from 1 to (length(argv))\r
+        move (replaces((mid(argv,1,l_01tmpInt)),argv2,argv3)) to argv2\r
+    loop\r
+    \r
+    function_return argv2\r
+end_function\r
+\r
+// Pad a string with zeros to the left\r
+function zeropad global string argv integer argv2 returns string\r
+    local string l_01tmpStr\r
+    \r
+    move "" to l_01tmpStr\r
+    move (repeat("0",(argv2-(length(trim(argv)))))) to l_01tmpStr\r
+    append l_01tmpStr (trim(argv))\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Padd a string with spaces to the left\r
+function leftpad global string argv integer argv2 returns string\r
+    local string l_01tmpStr\r
+    \r
+    move "" to l_01tmpStr\r
+    move (repeat(" ",(argv2-(length(trim(argv)))))) to l_01tmpStr\r
+    append l_01tmpStr (trim(argv))\r
+    \r
+    function_return l_01tmpStr\r
+end_function\r
+\r
+// Returns the string in reverse\r
+function reverse global string argv returns string\r
+    local string l_sReturn\r
+    local integer l_i l_iLen\r
+    \r
+    move (length(argv)) to l_iLen\r
+    move "" to l_sReturn\r
+    \r
+    for l_i from 0 to l_iLen\r
+        append l_sReturn (mid(argv,1,l_iLen-l_i))\r
+    loop\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+// Standard escaping via C standard.\r
+//\r
+// For PostgreSQL when no_backslash_quote is defined single quotes are \r
+// escaped per SQL standard by doubling '' rather than \' because in \r
+// some encodings multibyte characters have a last byte numerically \r
+// equivalent to ASCII escaped by backslash "\".\r
+// This should not be required if client encoding is LATIN1\r
+// and safe_encoding is set.\r
+function addslashes global string argv returns string\r
+    local string l_sReturn\r
+    \r
+    move (replaces("\",argv,"\\")) to l_sReturn\r
+    #IFDEF no_backslash_quote\r
+        move (replaces("'",l_sReturn,"''")) to l_sReturn\r
+    #ELSE\r
+        move (replaces("'",l_sReturn,"\'")) to l_sReturn\r
+    #ENDIF\r
+    move (replaces('"',l_sReturn,'\"')) to l_sReturn\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+// Standard escaping for quoted CSV standard\r
+function quotecsv global string argv returns string\r
+    local string l_sReturn\r
+    \r
+    move (replaces('"',argv,'""')) to l_sReturn\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+// Sanitize an integer for use in an sql statement. \r
+// This doesn't do anything other than make sure the value fits in the integer\r
+function sanitize_int global integer l_iInput integer bound returns integer\r
+    local integer l_iReturn\r
+    \r
+    move (integer(l_iInput)) to l_iReturn\r
+    \r
+    function_return l_iReturn   \r
+end_function\r
+\r
+// Sanitize an number for use in an sql statement. \r
+// This doesn't do anything other than make sure the value fits in the number\r
+function sanitize_num global number l_nInput returns integer\r
+    local number l_nReturn\r
+    \r
+    move (number(l_nInput)) to l_nReturn\r
+    \r
+    function_return l_nReturn   \r
+end_function\r
+\r
+// Sanitize a string. 3 Modes\r
+// SQL - this just does addslashes \r
+// SYSTEM - removes all characters that could be problematic at the console\r
+// PARANOID - removes all non alphanumeric characters and any aparent sql it is worried about.\r
+function sanitize_str global string l_sInput string l_sLevel returns string\r
+    local string l_sReturn\r
+    local integer l_i l_iCode l_iBadScore\r
+    \r
+    move (uppercase(trim(l_sLevel))) to l_sLevel\r
+    if ((l_sLevel <> "SQL") and (l_sLevel <> "SYSTEM") and (l_sLevel <> "PARANOID")) move "PARANOID" to l_sLevel\r
+    move "" to l_sReturn\r
+    \r
+    if (length(l_sInput) <> 0) begin\r
+        if (l_sLevel = "SQL") move (addslashes(l_sInput)) to l_sReturn\r
+        \r
+        if (l_sLevel = "SYSTEM") begin\r
+            move (replaceall("!=()<>/\|`'^~%$#;&",l_sInput,"")) to l_sReturn\r
+            move (replaces(character(10),l_sReturn,"")) to l_sReturn\r
+            move (replaces(character(13),l_sReturn,"")) to l_sReturn\r
+            move (replaces('"',l_sReturn,'')) to l_sReturn\r
+        end\r
+        if (l_sLevel = "PARANOID") begin\r
+            for l_i from 1 to (length(l_sInput))\r
+                move (ascii(mid(l_sInput,1,l_i))) to l_iCode\r
+                if (((l_iCode >= 48) and (l_iCode <= 57)) or ((l_iCode >= 65) and (l_iCode <=90)) or ((l_iCode >= 97) and (l_iCode <=122)) or (l_iCode = 32)) begin\r
+                    append l_sReturn (mid(l_sInput,1,l_i))\r
+                end\r
+            loop\r
+            \r
+            move 0 to l_iBadScore\r
+            if ((uppercase(l_sReturn) contains "DROP ") or (uppercase(l_sReturn) contains "CREATE ") or (uppercase(l_sReturn) contains "ALTER ") or (uppercase(l_sReturn) contains "TRUNCATE ") or (uppercase(l_sReturn) contains "COPY ")) begin\r
+                increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " TABLE ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " INDEX ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " DATABASE ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " GROUP ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " FUNCTION ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " RULE ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " AGGREGATE ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " TYPE ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " TRIGGER ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " OPERATOR ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " USER ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " SEQUENCE ") increment l_iBadScore\r
+            end\r
+            else if ((uppercase(l_sReturn) contains "GRANT ") or (uppercase(l_sReturn) contains "REVOKE ")) begin\r
+                increment l_iBadScore\r
+                if ((uppercase(l_sReturn) contains " ON ") and (uppercase(l_sReturn) contains " TO ")) increment l_iBadScore\r
+                if ((uppercase(l_sReturn) contains " ON ") and (uppercase(l_sReturn) contains " FROM ")) increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " ALL ") increment l_iBadScore\r
+                if (uppercase(l_sReturn) contains " ALL ") increment l_iBadScore\r
+                \r
+            end\r
+            else if ((uppercase(l_sReturn) contains "UPDATE ") or (uppercase(l_sReturn) contains "DELETE ")) begin\r
+                increment l_iBadScore\r
+                if (not (uppercase(l_sReturn)) contains " WHERE") increment l_iBadScore\r
+            end\r
+            if (l_iBadScore > 1) begin\r
+                move "" to l_sReturn\r
+            end\r
+        end\r
+        \r
+    end\r
+    else begin\r
+        move l_sInput to l_sReturn\r
+    end\r
+    \r
+    function_return l_sReturn   \r
+end_function\r
+\r
+// Return none blank of two strings\r
+function nbstring global string argv string argv2 returns string\r
+    if (argv <> "") function_return argv\r
+    else if (argv2 <> "") function_return argv2\r
+    else function_return ""\r
+end_function\r
+\r
+// Do transformation of xml based on xsl stylesheet\r
+// E.g. msxsl("\\somehost\bin\msxsl.exe", "c:\test.xml","c:\test.xsl","","c:\test.html")\r
+function msxsl global string engine string source string stylesheet string params string outfile returns string\r
+    local string l_sRemoteEngine l_sFile l_sOpts l_sReturn\r
+    local string l_iThrow l_iFileSize\r
+    \r
+    move (trim(engine)) to engine\r
+    move (trim(source)) to source\r
+    move (trim(stylesheet)) to stylesheet\r
+    move (trim(params)) to params\r
+    move (trim(outfile)) to outfile\r
+    move "" to l_sReturn \r
+    \r
+    // Attempt to keep a copy of the executable locally regardless of location\r
+    if not (g_bMsxslPresent) begin\r
+        if (does_exist(engine) = 1) begin\r
+            if (does_exist(g_sMsxslEngine) = 0) begin\r
+                move (fileopp("copy",engine,g_sMsxslEngine)) to l_iThrow\r
+                if (l_iThrow <> 0) move engine to g_sMsxslEngine\r
+            end\r
+            indicate g_bMsxslPresent true\r
+        end\r
+        else indicate g_bMsxslPresent false\r
+    end\r
+    \r
+    if (g_bMsxslPresent) begin\r
+        if (outfile = "") move (trim(cstring(get_local_temp(0)))+"msxsl."+(create_guid())) to l_sFile\r
+        else move outfile to l_sFile\r
+    \r
+        if ((source <> "") and (does_exist(source) = 1) and (stylesheet <> "") and (does_exist(stylesheet) = 1)) begin\r
+            move (source+" "+stylesheet+" -o "+l_sFile) to l_sOpts\r
+            if (params <> "") append l_sOpts " " params\r
+            move (create_proc(g_sMsxslEngine+" "+l_sOpts,0,0,0)) to l_iThrow\r
+\r
+            if (outfile = "") begin\r
+                move (file_size_bytes(l_sFile)) to l_iFileSize\r
+                direct_input channel default_file_channel l_sFile\r
+                    read_block channel default_file_channel l_sReturn l_iFileSize\r
+                close_input channel default_file_channel\r
+                move (fileopp("delete",l_sFile,"")) to l_iThrow\r
+            end\r
+            else move outfile to l_sReturn\r
+        end\r
+    end\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+//-------------------------------------------------------------------------\r
+// Classes\r
+//-------------------------------------------------------------------------\r
+\r
+// String tokenizer class\r
+//\r
+// Send message methods:\r
+//    set_string\r
+//\r
+// Set methods:\r
+//    token_value \r
+//\r
+// Get methods:\r
+//    token_value \r
+//    token_count\r
+//    next_token\r
+//    token_ptr\r
+//\r
+// Example usage:\r
+//\r
+//    object myToken is a StringTokenizer\r
+//    end_object\r
+//\r
+//    send set_string to (myToken(current_object)) tmp ","\r
+//\r
+//    get token_count of (myToken(current_object)) to x\r
+//\r
+//    for i from 0 to x\r
+//        get token_value of (myToken(current_object)) item i to buf\r
+//        showln buf\r
+//    loop\r
+//\r
+//    repeat\r
+//        get next_token of (myToken(current_object)) to buf\r
+//        showln buf\r
+//        get token_ptr of (myToken(current_object)) to i\r
+//    until (i = -1)\r
+\r
+class StringTokenizer is an array\r
+    procedure construct_object integer argc\r
+            forward send construct_object\r
+            property integer c_iTokens public argc\r
+            property integer c_iTokenOn\r
+    end_procedure\r
+\r
+    procedure set_string string inString string inSep\r
+        local integer l_iTokens l_iPos l_iPad\r
+        local string l_01tmpStr l_02tmpStr\r
+\r
+        move -1 to l_iTokens\r
+        move (trim(inString)) to l_01tmpStr\r
+        move (length(inSep)) to l_iPad\r
+        move 2 to l_iPos\r
+        \r
+        while (l_01tmpStr <> "") \r
+            if (inSep <> "") move (pos(inSep,l_01tmpStr)) to l_iPos\r
+                \r
+            move (left(l_01tmpStr, (l_iPos-1))) to l_02tmpStr\r
+            if (l_01tmpStr = l_02tmpStr) move "" to l_01tmpStr\r
+            else move (right(l_01tmpStr,length(l_01tmpStr)-(l_iPos+l_iPad-1))) to l_01tmpStr\r
+\r
+            increment l_iTokens\r
+            forward set array_value item l_iTokens to l_02tmpStr\r
+        end \r
+    \r
+        set c_iTokenOn to 0\r
+        set c_iTokens to l_iTokens\r
+    end_procedure\r
+\r
+    procedure set token_value integer itemx string val\r
+        forward set array_value item itemx to val\r
+    end_procedure\r
+\r
+    function token_value integer itemx returns string\r
+        local string l_sBuf                \r
+        forward get string_value item itemx to l_sBuf\r
+        function_return l_sBuf\r
+    end_function \r
+\r
+    function next_token returns string\r
+        local string l_sBuf\r
+        local string l_iTokenOn l_iTokens\r
+        \r
+        get c_iTokenOn to l_iTokenOn                \r
+        get c_iTokens to l_iTokens\r
+        forward get string_value item l_iTokenOn to l_sBuf\r
+        \r
+        if (l_iTokenOn < l_iTokens) set c_iTokenOn to (l_iTokenOn+1)\r
+        else set c_iTokenOn to -1\r
+        function_return l_sBuf\r
+    end_function \r
+\r
+    function token_ptr returns integer\r
+        local integer l_iTokenOn\r
+        get c_iTokenOn to l_iTokenOn\r
+        function_return l_iTokenOn\r
+    end_function\r
+    \r
+    function token_count returns integer\r
+        local integer l_iTokens\r
+        get c_iTokens to l_iTokens\r
+        function_return l_iTokens\r
+    end_function\r
+end_class\r
diff --git a/src/df32/tcpcomm.h b/src/df32/tcpcomm.h
new file mode 100644 (file)
index 0000000..17c2ce5
--- /dev/null
@@ -0,0 +1,26 @@
+//-------------------------------------------------------------------------\r
+// tcpcomm.h\r
+//      This file contains definitions of "Win32" api functions provided by\r
+//      the df32func.dll dynamic link library.\r
+//\r
+// This file is to be included when using socket networking in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+//\r
+// df32func/tcpcomm.h\r
+//-------------------------------------------------------------------------\r
+\r
+Define __tcpcomm_h__\r
+\r
+//-------------------------------------------------------------------------\r
+// External functions\r
+//-------------------------------------------------------------------------\r
+\r
+external_function ClientSocket "ClientSocket" df32func.dll dword port string host returns integer\r
+external_function ServerSocket "ServerSocket" df32func.dll dword port returns integer\r
+external_function AcceptClient "AcceptClient" df32func.dll returns integer\r
+external_function Send "Send" df32func.dll dword socket string data returns integer\r
+external_function Receive "Receive" df32func.dll dword socket pointer dataOut returns integer\r
+external_function CloseConnection "CloseConnection" df32func.dll dword socket returns integer\r
+external_function PseudoRand "PseudoRand" df32func.dll dword w returns integer\r
+external_function RdtscRand "RdtscRand" df32func.dll returns integer\r
diff --git a/src/df32/tstamp.inc b/src/df32/tstamp.inc
new file mode 100644 (file)
index 0000000..e5519a3
--- /dev/null
@@ -0,0 +1,515 @@
+//-------------------------------------------------------------------------\r
+// tstamp.inc\r
+//      This file contains some DataFlex 3.2 Console Mode functions\r
+//      to provide extended timestamp and timezone manipulation capabilities.\r
+//      Depends on functions in both win32.inc and string.inc/\r
+//\r
+// This file is to be included in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/tstamp.inc\r
+//-------------------------------------------------------------------------\r
+\r
+//-------------------------------------------------------------------------\r
+// Global tokenizer used for splitting timezon data\r
+//-------------------------------------------------------------------------\r
+object tzTok is a StringTokenizer\r
+end_object\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Convert a textual timestamp to a posix number\r
+// Also see posixtime and posixtime_reverse in date.inc\r
+function timestemp_to_posix global string inTs returns number\r
+        local number l_posix l_hr l_min l_sec l_msec\r
+        local date l_date\r
+\r
+        // leap seconds not coded        \r
+        if ((length(inTs) < 10) or (mid(inTs, 1, 3) <> "/") or (mid(inTs, 1, 6)  <> "/") or (mid(inTs, 1, 11)  <> " ")) begin\r
+            custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY"\r
+        end\r
+        if (((length(inTs) >= 16) and (mid(inTs, 1, 14)  <> ":")) or ((length(inTs) >= 19) and (mid(inTs, 1, 17)  <> ":"));\r
+            or ((length(inTs) >= 21) and (mid(inTs, 1, 20)  <> "."))) begin\r
+            custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY HH:mm:SS.mss"\r
+        end\r
+        \r
+        move (left(inTs,(pos(" ",inTs)-1))) to l_date\r
+        if (length(inTs) >= 13) move (mid(inTs, 2, 12)) to l_hr\r
+        else move 0 to l_hr\r
+        if (length(inTs) >= 16) move (mid(inTs, 2, 15)) to l_min\r
+        else move 0 to l_min\r
+        if (length(inTs) >= 19) move (mid(inTs, 2, 18)) to l_sec\r
+        else move 0 to l_sec\r
+        if (length(inTs) >= 21) move (mid(inTs, 3, 21)) to l_msec\r
+        else move 0 to l_msec\r
+        \r
+        if ((l_hr > 23) or (l_min > 59) or (l_sec > 59) or (l_msec > 999);\r
+            or (l_hr < 0) or (l_min < 0) or (l_sec < 0) or (l_msec < 0)) begin\r
+            custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP\r
+        end\r
+        \r
+        calc (((integer(l_date))-(integer(date("01/01/1970"))))*86400) to l_posix\r
+        calc (((((l_hr*60)+l_min)*60)+l_sec)+(l_msec/1000)+l_posix) to l_posix\r
+        \r
+        function_return l_posix\r
+end_function\r
+\r
+// Convert a posix number to a textual timestamp\r
+function posix_to_timestamp global number argv returns string\r
+        local date l_date\r
+        local number l_subt \r
+        local integer l_hr l_min l_sec l_msec\r
+        local string l_posix_reverse\r
+        \r
+        // leap seconds not coded\r
+        calc ((argv/86400)+(integer(date("01/01/1970")))) to l_date\r
+        calc (argv-(((integer(l_date))-(integer(date("01/01/1970"))))*86400)) to l_subt\r
+        calc (l_subt/3600) to l_hr\r
+        calc ((l_subt-(l_hr*3600))/60) to l_min\r
+        calc (l_subt-(((l_hr*60)+l_min)*60)) to l_sec\r
+        calc ((l_subt-((((l_hr*60)+l_min)*60)+l_sec))*1000) to l_msec\r
+        \r
+        if ((l_hr > 23) or (l_min > 59) or (l_sec > 59) or (l_msec > 999);\r
+            or (l_hr < 0) or (l_min < 0) or (l_sec < 0) or (l_msec < 0)) begin\r
+            custom_error ERROR_CODE_INVALID_POSIX_NUMBER$ ERROR_MSG_INVALID_POSIX_NUMBER argv\r
+        end        \r
+                \r
+    move "" to l_posix_reverse\r
+    move (string(l_date)+" "+zeropad(l_hr,2)+":"+zeropad(l_min,2)+":"+zeropad(l_sec,2)+"."+zeropad(l_msec,3)) to l_posix_reverse\r
+           \r
+        function_return l_posix_reverse\r
+end_function\r
+\r
+// Adjust supplied timestamp by supplied milliseconds\r
+function timestamp_adjust global string inTs number inMSeconds returns string\r
+    local string retTimestamp\r
+    local number nPosix\r
+    \r
+    move (timestemp_to_posix(inTs)) to nPosix\r
+    move (posix_to_timestamp(nPosix+(inMSeconds/1000))) to retTimestamp\r
+    \r
+    function_return retTimestamp\r
+end_function\r
+\r
+// Limited as we'd need to know the actual timestamp referred to to do months, years etc.\r
+// Supports millisecond, second, minute, hour, day, week\r
+function interval_to_posix global string argv returns number\r
+    local number l_value l_return\r
+    local integer l_i\r
+    local string l_unit l_interval  l_numerics\r
+    \r
+    move (trim(argv)) to l_interval\r
+    move 0 to l_return\r
+    \r
+    if (length(l_interval) <> 0) begin\r
+        move 1 to l_i\r
+        while (l_i < length(l_interval))\r
+            move 0 to l_value\r
+            move "" to l_numerics\r
+            move "" to l_unit\r
+            while ((ascii(mid(l_interval, 1, l_i)) > 47) and (ascii(mid(l_interval, 1, l_i)) < 58))\r
+                append l_numerics (mid(l_interval, 1, l_i))\r
+                increment l_i\r
+            loop\r
+            while (ascii(mid(l_interval, 1, l_i)) = 32)\r
+                increment l_i\r
+            loop\r
+\r
+            while ((ascii(mid(l_interval, 1, l_i)) > 64) and (ascii(mid(l_interval, 1, l_i)) < 91);\r
+                or (ascii(mid(l_interval, 1, l_i)) > 96) and (ascii(mid(l_interval, 1, l_i)) < 123))\r
+                append  l_unit (mid(l_interval, 1, l_i))\r
+                increment l_i\r
+            loop\r
+\r
+            move (lowercase(trim(l_unit))) to l_unit        \r
+            case begin\r
+                case ((mid(l_unit,11,1) = "millisecond") or (mid(l_unit,2,1) = "ms")) move (l_numerics/number(1000)) to l_value\r
+                case break\r
+                case ((mid(l_unit,6,1) = "second") or (mid(l_unit,1,1) = "s")) move l_numerics to l_value\r
+                case break\r
+                case ((mid(l_unit,6,1) = "minute") or (mid(l_unit,1,1) = "m")) move (l_numerics*60) to l_value\r
+                case break          \r
+                case ((mid(l_unit,4,1) = "hour") or (mid(l_unit,1,1) = "h")) move (l_numerics*3600) to l_value                  \r
+                case break                      \r
+                case ((mid(l_unit,3,1) = "day") or (mid(l_unit,1,1) = "d")) move (l_numerics*86400) to l_value\r
+                case break                                  \r
+                case ((mid(l_unit,4,1) = "week") or (mid(l_unit,1,1) = "w")) move (l_numerics*604800) to l_value\r
+                case break                                  \r
+            case end\r
+\r
+            move (l_return+l_value) to l_return\r
+        loop\r
+    end\r
+    \r
+    function_return l_return\r
+end_function\r
+\r
+// Adjust supplied timestamp by supplied interval\r
+// Supports microsecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium\r
+// Negative sinage is indicated by "ago", words without preceeding units are treated as noise. E.g:\r
+// timestamp_adjust_interval("28/02/2009 09:00:00.000", "1century 2years 1month 1day 1hour 1minute 1second and 500 milliseconds ago")\r
+// Note that actual timestamps will be bound by posix and dataflex timestamp implementations.\r
+function timestamp_adjust_interval global string inTs string inInterval returns string\r
+    local string retTimestamp tmpTimestamp l_unit l_interval  l_numerics\r
+    local number nPosix l_value l_return l_year l_mon l_day\r
+    local integer l_i l_iThrow l_iSign\r
+    \r
+    if ((length(inTs) < 10) or (mid(inTs, 1, 3) <> "/") or (mid(inTs, 1, 6)  <> "/")) begin\r
+        custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY"\r
+    end\r
+    \r
+    move (mid(inTs, 2, 1)) to l_day\r
+    move (mid(inTs, 2, 4)) to l_mon\r
+    move (mid(inTs, 4, 7)) to l_year\r
+    \r
+    if (lowercase(inInterval) contains "ago");\r
+        move -1 to l_iSign\r
+    else;\r
+        move 1 to l_iSign\r
+    \r
+    move (trim(inInterval)) to l_interval\r
+    move 0 to l_return\r
+    \r
+    if (length(l_interval) <> 0) begin\r
+        move 1 to l_i\r
+        while (l_i < length(l_interval))\r
+            move 0 to l_value\r
+            move "" to l_numerics\r
+            move "" to l_unit\r
+            while ((ascii(mid(l_interval, 1, l_i)) > 47) and (ascii(mid(l_interval, 1, l_i)) < 58))\r
+                append l_numerics (mid(l_interval, 1, l_i))\r
+                increment l_i\r
+            loop\r
+            while (ascii(mid(l_interval, 1, l_i)) = 32)\r
+                increment l_i\r
+            loop\r
+            while ((ascii(mid(l_interval, 1, l_i)) > 64) and (ascii(mid(l_interval, 1, l_i)) < 91);\r
+                or (ascii(mid(l_interval, 1, l_i)) > 96) and (ascii(mid(l_interval, 1, l_i)) < 123))\r
+                append  l_unit (mid(l_interval, 1, l_i))\r
+                increment l_i\r
+            loop\r
+            move (lowercase(trim(l_unit))) to l_unit        \r
+            case begin\r
+                case ((mid(l_unit,10,1) = "millennium") or (mid(l_unit,6,1) = "millen")) move (l_year+(l_numerics*1000*l_iSign)) to l_year\r
+                case break\r
+                case ((mid(l_unit,7,1) = "century") or (mid(l_unit,1,1) = "c")) move (l_year+(l_numerics*100*l_iSign)) to l_year\r
+                case break\r
+                case ((mid(l_unit,6,1) = "decade") or (mid(l_unit,3,1) = "dec")) move (l_year+(l_numerics*10*l_iSign)) to l_year\r
+                case break\r
+                case ((mid(l_unit,4,1) = "year") or (mid(l_unit,1,1) = "y")) move (l_year+(l_numerics*l_iSign)) to l_year\r
+                case break\r
+                case ((mid(l_unit,5,1) = "month") or (mid(l_unit,3,1) = "mon")) move (l_mon+(l_numerics*l_iSign)) to l_mon\r
+                case break\r
+                case ((mid(l_unit,11,1) = "millisecond") or (mid(l_unit,2,1) = "ms")) move (l_numerics/number(1000)) to l_value\r
+                case break\r
+                case ((mid(l_unit,6,1) = "second") or (mid(l_unit,1,1) = "s")) move l_numerics to l_value\r
+                case break\r
+                case ((mid(l_unit,6,1) = "minute") or (mid(l_unit,3,1) = "min")) move (l_numerics*60) to l_value\r
+                case break          \r
+                case ((mid(l_unit,4,1) = "hour") or (mid(l_unit,1,1) = "h")) move (l_numerics*3600) to l_value                  \r
+                case break                      \r
+                case ((mid(l_unit,3,1) = "day") or (mid(l_unit,1,1) = "d")) move (l_numerics*86400) to l_value\r
+                case break                                  \r
+                case ((mid(l_unit,4,1) = "week") or (mid(l_unit,1,1) = "w")) move (l_numerics*604800) to l_value\r
+                case break                                  \r
+            case end\r
+            move (l_return+l_value) to l_return\r
+        loop\r
+    end \r
+    \r
+    move (timestemp_to_posix(zeropad(l_day,2)+"/"+zeropad(l_mon,2)+"/"+zeropad(l_year,4)+mid(inTs,length(inTs)-10,11))) to nPosix\r
+    move (posix_to_timestamp(nPosix+(l_return*l_iSign))) to retTimestamp\r
+    \r
+    function_return retTimestamp\r
+end_function\r
+\r
+// This takes the day of the week and month occourance values from a SYSTEMTIME \r
+// in a _TIME_ZONE_INFORMATION and works out the correct day of the month\r
+// See description under "DaylightDate" here https://msdn.microsoft.com/en-us/library/ms724253.aspx\r
+function get_day_of_month_for_daylight_savings global integer inYear integer inMonth integer inDayOfWeek integer inDay returns integer\r
+    local integer l_dom l_i\r
+    local date l_date\r
+    \r
+    if (inDayOfWeek = 0) move 7 to inDayOfWeek\r
+    \r
+    move ("01/"+zeropad(inMonth,2)+"/"+zeropad(inYear,4)) to l_date\r
+    \r
+    while (get_day_score(l_date) <> inDayOfWeek)\r
+        increment l_date\r
+    loop\r
+    \r
+    if (integer(mid(l_date, 2, 4)) = inMonth);\r
+        move (mid(l_date, 2, 1)) to l_dom           \r
+    \r
+    for l_i from 1 to (inDay-1)\r
+        calc (l_date+7) to l_date\r
+        \r
+    if (integer(mid(l_date, 2, 4)) = inMonth);\r
+        move (mid(l_date, 2, 1)) to l_dom           \r
+    loop\r
+    \r
+    function_return l_dom\r
+end_function\r
+\r
+// Get local system time and starts to pull values to adjust to UTC (needs finishing)\r
+function systemtime_utc global returns string\r
+    local string sSystemTime sTimeZoneInformation sStdName sDlName sFormattedTime sFormattedDate sTs\r
+    local integer iSuccess iBias iStdBias iDlBias iBiasNow iLenCcTime iLenCcDate iDataLength\r
+    local pointer lpSystemTime lpTimeZoneInformation lpsFormattedTime lpsFormattedDate\r
+\r
+    // Get the current system local time\r
+    zerotype _SYSTEMTIME to sSystemTime\r
+    getaddress of sSystemTime to lpSystemTime\r
+\r
+    move (GetSystemTime(lpSystemTime)) to iSuccess\r
+\r
+    if (iSuccess <> 0) begin\r
+        // Get the current system timezone information\r
+        zerotype _TIME_ZONE_INFORMATION to sTimeZoneInformation\r
+        getaddress of sTimeZoneInformation to lpTimeZoneInformation\r
+\r
+        move (GetTimeZoneInformation(lpTimeZoneInformation)) to iSuccess\r
+            \r
+        if (iSuccess = TIME_ZONE_ID_INVALID) begin\r
+            custom_error ERROR_CODE_INVALID_SYSTEM_TIMEZONE$ ERROR_MSG_INVALID_SYSTEM_TIMEZONE\r
+        end\r
+        else begin\r
+        getbuff from sTimeZoneInformation at TIME_ZONE_INFORMATION.Bias to iBias\r
+        move (cstring(to_ascii(mid(sTimeZoneInformation, 64, 5)))) to sStdName //getbuff from sTimeZoneInformation at TIME_ZONE_INFORMATION.StandardName to sStdName //UTF-16/wchar                      \r
+        getbuff from sTimeZoneInformation at TIME_ZONE_INFORMATION.StandardBias to iStdBias\r
+        move (cstring(to_ascii(mid(sTimeZoneInformation, 64, 89)))) to sDlName //getbuff from sTimeZoneInformation at TIME_ZONE_INFORMATION.DaylightName to sDlName //UTF-16/wcharsDlName \r
+        getbuff from sTimeZoneInformation at TIME_ZONE_INFORMATION.DaylightBias to iDlBias\r
+\r
+        zerostring 255 to sFormattedTime\r
+        getaddress of sFormattedTime to lpsFormattedTime\r
+        move (length(sFormattedTime)) to iLenCcTime\r
+        move (GetTimeFormat("LOCALE_USER_DEFAULT", 0, lpSystemTime, 0, lpsFormattedTime, iLenCcTime)) to iDataLength                \r
+\r
+        zerostring 255 To sFormattedDate\r
+        getaddress of sFormattedDate To lpsFormattedDate\r
+        move (length(sFormattedDate)) to iLenCcDate\r
+        move (GetDateFormat("LOCALE_USER_DEFAULT", 0, lpSystemTime, 0, lpsFormattedDate, iLenCcDate)) to iDataLength\r
+\r
+        // Work out bias and apply to get UTC\r
+        if (iSuccess = TIME_ZONE_ID_DAYLIGHT) begin\r
+            move (iBias+iDlBias) to iBiasNow\r
+        end\r
+        else begin\r
+            move (iBias+iStdBias) to iBiasNow\r
+        end\r
+        \r
+        move (cstring(sFormattedDate) * cstring(sFormattedTime)) to sTs\r
+        move (timestamp_adjust(sTs, iBiasNow*60000)) to sTs\r
+    end\r
+    end\r
+\r
+    function_return sTs\r
+end_function\r
+\r
+// Returns UTC BIAS in minutes\r
+function get_bias global string inDestTz integer inYear integer inMon integer inDay integer inHr integer inMin integer inSec integer inIsUTC returns integer\r
+    local string sTimeZone sResult sBuf sDaylightDate sDaylightTime sStandardDate sStandardTime StdTs DltTs inTs\r
+    local integer iSuccess iBiasNow iBias iStdBias iDaylightBias iIsDaylightSaving iThrow iTmp\r
+    local integer iEYear iEMon iEDay iEDOW iEHr iEMin iESec iBYear iBMon iBDay iBDOW iBHr iBMin iBSec iEDOM iBDOM\r
+    local number nTO nBO nEO StdPo DltPo inPo\r
+    local pointer lpTimeZone lpResult\r
+\r
+    ASSERT ((inIsUTC >= 0) and (inIsUTC <= 1)) "Unsupported mode, inIsUTC must be either 1 or 0"\r
+            \r
+    move 0 to iIsDaylightSaving\r
+    move (trim(inDestTz)) to sTimeZone    \r
+    \r
+    if (sTimeZone <> "") begin\r
+        if (show_debug_lines = 1);\r
+            showln "Timezone:          " sTimeZone\r
+    \r
+        getaddress of sTimeZone to lpTimeZone\r
+                \r
+        zerostring 128 to sResult\r
+        getaddress of sResult to lpResult\r
+                \r
+        move (GetTzi(lpTimeZone, lpResult)) to iSuccess\r
+                    \r
+        if (iSuccess = -1) begin\r
+        \r
+            send set_string to (tzTok(current_object)) sResult ","\r
+            get token_value of (tzTok(current_object)) item 0 to iBias\r
+            get token_value of (tzTok(current_object)) item 1 to iStdBias\r
+            get token_value of (tzTok(current_object)) item 2 to iDaylightBias\r
+            get token_value of (tzTok(current_object)) item 3 to sStandardDate\r
+            get token_value of (tzTok(current_object)) item 4 to sStandardTime\r
+            get token_value of (tzTok(current_object)) item 5 to sDaylightDate\r
+            get token_value of (tzTok(current_object)) item 6 to sDaylightTime\r
+            \r
+            // Once all of our data has been retrieved we need to determine daylight saving time\r
+            //showln  sDaylightDate " " sDaylightTime " = " sStandardDate " " sStandardTime\r
+\r
+            send set_string to (tzTok(current_object)) sDaylightDate "/"            \r
+            get token_value of (tzTok(current_object)) item 0 to iBYear\r
+            get token_value of (tzTok(current_object)) item 1 to iBMon\r
+            get token_value of (tzTok(current_object)) item 2 to iBDay\r
+            get token_value of (tzTok(current_object)) item 3 to iBDOW\r
+            \r
+            send set_string to (tzTok(current_object)) sStandardDate "/"            \r
+            get token_value of (tzTok(current_object)) item 0 to iEYear\r
+            get token_value of (tzTok(current_object)) item 1 to iEMon\r
+            get token_value of (tzTok(current_object)) item 2 to iEDay\r
+            get token_value of (tzTok(current_object)) item 3 to iEDOW\r
+            \r
+            ASSERT ((iBMon <> 0) and (iEMon <> 0)) "Daylight saving not supported"\r
+            \r
+            if (show_debug_lines = 1) begin\r
+                if ((iBMon = 0) or (iEMon = 0));\r
+                    showln "Supports Dls:      no" \r
+                else;\r
+                    showln "Supports Dls:      yes" \r
+            end         \r
+                                            \r
+            if ((iBMon <> 0) and (iEMon <> 0)) begin\r
+                if ((iBYear = 0) or (iBYear = inYear)) begin\r
+                \r
+                    move (get_day_of_month_for_daylight_savings((iBYear max inYear),iBMon,iBDOW,iBday)) to iBDOM\r
+                    move (get_day_of_month_for_daylight_savings((iEYear max inYear),iEMon,iEDOW,iEday)) to iEDOM              \r
+                    \r
+                    send set_string to (tzTok(current_object)) sDaylightTime ":"\r
+                    get token_value of (tzTok(current_object)) item 0 to iBHr\r
+                    get token_value of (tzTok(current_object)) item 1 to iBMin\r
+                    get token_value of (tzTok(current_object)) item 2 to iBSec\r
+\r
+                    send set_string to (tzTok(current_object)) sStandardTime ":"\r
+                    get token_value of (tzTok(current_object)) item 0 to iEHr\r
+                    get token_value of (tzTok(current_object)) item 1 to iEMin\r
+                    get token_value of (tzTok(current_object)) item 2 to iESec\r
+\r
+                    move (zeropad(iBDOM,2)+"/"+zeropad(iBMon,2)+"/"+string(iEYear max inYear)+" "+zeropad(iBHr,2)+":"+zeropad(iBMin,2)+":"+zeropad(iBSec,2)) to DltTs\r
+                    move (zeropad(iEDOM,2)+"/"+zeropad(iEMon,2)+"/"+string(iEYear max inYear)+" "+zeropad(iEHr,2)+":"+zeropad(iEMin,2)+":"+zeropad(iESec,2)) to StdTs\r
+                    move (zeropad(inDay,2)+"/"+zeropad(inMon,2)+"/"+string(inYear)+" "+zeropad(inHr,2)+":"+zeropad(inMin,2)+":"+zeropad(inSec,2)) to inTs\r
+                    \r
+                    move (timestemp_to_posix(DltTs)) to DltPo\r
+                    move (timestemp_to_posix(StdTs)) to StdPo\r
+                    move (timestemp_to_posix(inTs)+(iBias*-60*inIsUTC)) to inPo\r
+                    \r
+                    if (show_debug_lines = 1) begin\r
+                        showln "InTimestamp:       " inTs\r
+                        showln "CmpTimestamp:      " (posix_to_timestamp(inPo))\r
+                        showln "DaylightTimestamp: " DltTs " Offset="  (iBias+iDaylightBias)                    \r
+                        showln "StandardTimestamp: " StdTs " Offset="  (iBias+iStdBias)\r
+                    end\r
+                    \r
+                    if (DltPo < StdPo) begin\r
+                        if ((inPo >= DltPo) and (inPo < StdPo)) move 1 to iIsDaylightSaving\r
+                    end\r
+                    else begin\r
+                        if not ((inPo >= StdPo) and (inPo < DltPo)) move 1 to iIsDaylightSaving\r
+                    end\r
+                end\r
+                \r
+            end\r
+            \r
+            // If the clocks go forward at 1.00am then the 1.00am-1.59am doesn't exist in localtime; \r
+            // conversins back and forth between nonexistent times will look wrong, but should never occour\r
+            // If the clocks go back at 1.00am then 1.00am effectively occours twice \r
+            // More info: http://www.timeanddate.com/time/dst/transition.html\r
+            \r
+            // Now we can figure out the actual bias\r
+            if (iIsDaylightSaving = 1) begin\r
+                move (iBias+iDaylightBias) to iBiasNow\r
+                if (show_debug_lines = 1) begin\r
+                    showln "Zone currently in daylight saving"\r
+                end\r
+            end\r
+            else begin\r
+                move (iBias+iStdBias) to iBiasNow\r
+            end\r
+            if (show_debug_lines = 1) begin\r
+                showln "Bias:              " iBiasNow\r
+            end\r
+            \r
+            send destroy_object to tzTok\r
+        end\r
+        else begin\r
+            custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP\r
+        end        \r
+    end\r
+\r
+    function_return iBiasNow\r
+end_function\r
+\r
+// Returns UTC time converted from the current time in the passed timezone \r
+function get_utc_time_from_timezone_time global string inDestTz string inTs returns string\r
+    local integer l_bias\r
+    local string l_ts\r
+    local integer inGmtYear inGmtMon inGmtDay inGmtHr inGmtMin inGmtSec \r
+\r
+    if ((length(inTs) < 10) or (mid(inTs, 1, 3) <> "/") or (mid(inTs, 1, 6)  <> "/") or (mid(inTs, 1, 11)  <> " ")) begin\r
+        custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY"\r
+    end\r
+    if (((length(inTs) >= 16) and (mid(inTs, 1, 14)  <> ":")) or ((length(inTs) >= 19) and (mid(inTs, 1, 17)  <> ":"));\r
+        or ((length(inTs) >= 21) and (mid(inTs, 1, 20)  <> "."))) begin\r
+        custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY HH:mm:SS.mss"\r
+    end\r
+            \r
+    move (mid(inTs, 2, 1)) to inGmtDay\r
+    move (mid(inTs, 2, 4)) to inGmtMon\r
+    move (mid(inTs, 4, 7)) to inGmtyear\r
+    \r
+    if (length(inTs) >= 13) move (mid(inTs, 2, 12)) to inGmtHr\r
+    else move 0 to inGmtHr\r
+    if (length(inTs) >= 16) move (mid(inTs, 2, 15)) to inGmtMin\r
+    else move 0 to inGmtMin\r
+    if (length(inTs) >= 19) move (mid(inTs, 2, 18)) to inGmtSec\r
+    else move 0 to inGmtSec\r
+    \r
+    move (get_bias(inDestTz, inGmtYear, inGmtMon, inGmtDay, inGmtHr, inGmtMin, inGmtSec, 0)) to l_bias\r
+    move (zeropad(inGmtDay,2)+"/"+zeropad(inGmtMon,2)+"/"+zeropad(inGmtYear,4)+" "+zeropad(inGmtHr,2)+":"+zeropad(inGmtMin,2)+":"+zeropad(inGmtSec,2)) to l_ts\r
+    \r
+    move (timestamp_adjust(l_ts, l_bias*60000)) to l_ts\r
+    \r
+    function_return l_ts\r
+end_function\r
+\r
+//Returns current time in the passed timezone from the time passed as UTC\r
+function get_timezone_time_from_utc_time global string inDestTz string inTs returns string\r
+    local integer l_bias\r
+    local string l_ts\r
+    local integer inUtcYear inUtcMonth inUtcDay inUtcHr inUtcMin inUtcSec \r
+\r
+    if ((length(inTs) < 10) or (mid(inTs, 1, 3) <> "/") or (mid(inTs, 1, 6)  <> "/") or (mid(inTs, 1, 11)  <> " ")) begin\r
+        custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY"\r
+    end\r
+    if (((length(inTs) >= 16) and (mid(inTs, 1, 14)  <> ":")) or ((length(inTs) >= 19) and (mid(inTs, 1, 17)  <> ":"));\r
+        or ((length(inTs) >= 21) and (mid(inTs, 1, 20)  <> "."))) begin\r
+        custom_error ERROR_CODE_INVALID_TIMESTAMP$ ERROR_MSG_INVALID_TIMESTAMP ERROR_DETAIL_INVALID_TIMESTAMP "DD/MM/YYYY HH:mm:SS.mss"\r
+    end\r
+            \r
+    move (mid(inTs, 2, 1)) to inUtcDay\r
+    move (mid(inTs, 2, 4)) to inUtcMonth\r
+    move (mid(inTs, 4, 7)) to inUtcyear\r
+    \r
+    if (length(inTs) >= 13) move (mid(inTs, 2, 12)) to inUtcHr\r
+    else move 0 to inUtcHr\r
+    if (length(inTs) >= 16) move (mid(inTs, 2, 15)) to inUtcMin\r
+    else move 0 to inUtcMin\r
+    if (length(inTs) >= 19) move (mid(inTs, 2, 18)) to inUtcSec\r
+    else move 0 to inUtcSec\r
+            \r
+    move (get_bias(inDestTz, inUtcYear, inUtcMonth, inUtcDay, inUtcHr, inUtcMin, inUtcSec, 1)) to l_bias\r
+    move (zeropad(inUtcDay,2)+"/"+zeropad(inUtcMonth,2)+"/"+zeropad(inUtcYear,4)+" "+zeropad(inUtcHr,2)+":"+zeropad(inUtcMin,2)+":"+zeropad(inUtcSec,2)) to l_ts\r
+    \r
+    move (timestamp_adjust(l_ts, l_bias*-60000)) to l_ts\r
+    \r
+    function_return l_ts\r
+end_function\r
+\r
+//Convert a timestamp from one local zone to another\r
+function get_timezone_time_from_timezone_time global string inSourceTz string inDestTz string inTs returns string\r
+    local string l_ts\r
+    \r
+    move (get_timezone_time_from_utc_time(inDestTz, (get_utc_time_from_timezone_time(inSourceTz, inTs)))) to l_ts\r
+    \r
+    function_return l_ts\r
+end_function\r
+\r
diff --git a/src/df32/win32.h b/src/df32/win32.h
new file mode 100644 (file)
index 0000000..64553e8
--- /dev/null
@@ -0,0 +1,713 @@
+//-------------------------------------------------------------------------\r
+// win32.h\r
+//      This file contains definitions of "Win32" api functions as well as\r
+//      their related constants and structs.  These functions are exposed as\r
+//      dynamic link libraries provided on systems running Windows XP or greater.\r
+//\r
+// This file is to be included when using Win32 capabilities in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/win32.h\r
+//-------------------------------------------------------------------------\r
+\r
+Define __win32_h__\r
+\r
+//-------------------------------------------------------------------------\r
+// External functions\r
+//-------------------------------------------------------------------------\r
+\r
+external_function GetDateFormat "GetDateFormatA" kernel32.dll dword LCID dword dwFlags pointer lpsSystemTime pointer lpFormat pointer lpDateStr integer cchDate returns integer\r
+external_function GetTimeFormat "GetTimeFormatA" kernel32.dll dword LCID dword dwFlags pointer lpsSystemTime pointer lpFormat pointer lpTimeStr integer cchTime returns integer\r
+external_function GetFileTime "GetFileTime" kernel32.dll handle hFileHandle pointer lpCreationTime pointer lpLastAccessTime pointer lpLastWriteTime returns integer\r
+external_function FileTimeToSystemTime "FileTimeToSystemTime" kernel32.dll pointer lpFileTime Pointer lpSystemTime returns integer\r
+external_function FileTimeToLocalFileTime "FileTimeToLocalFileTime" kernel32.dll pointer lpFileTime Pointer lpSystemTime returns integer\r
+external_function FindFirstFile "FindFirstFileA" kernel32.dll pointer lpFileName pointer lpFindFileData returns handle\r
+external_function FindNextFile "FindNextFileA" kernel32.dll handle hFindFile pointer lpFindFileData returns integer\r
+external_function FindClose "FindClose" kernel32.dll handle hFindFile returns integer\r
+external_function LockFile "LockFile" kernel32.dll handle hFile dword dwFileOffsetLow dword dwFileOffsetHigh dword nNumberOfBytesToLockLow dword nNumberOfBytesToLockHigh returns integer\r
+external_function UnlockFile "UnlockFile" kernel32.dll handle hFile dword dwFileOffsetLow dword dwFileOffsetHigh dword nNumberOfBytesToLockLow dword nNumberOfBytesToLockHigh returns integer\r
+external_function SHFileOperation "SHFileOperationA" shell32.dll pointer lpFileOp returns integer\r
+external_function32 GetTempPath "GetTempPathA" kernel32.dll integer nBufferLength pointer lpBuffer_ptr returns integer\r
+external_function GetSystemDirectory "GetSystemDirectoryA" kernel32.dll pointer lpBuffer integer uSize returns integer\r
+external_function32 mciSendString "mciSendStringA" winmm.dll pointer lpstrCommand pointer lpstrReturnString integer uReturnLength integer hwndCallback returns integer\r
+external_function ExitProcessEx  "ExitProcess" Kernel32.dll integer iExitCode returns integer\r
+external_function GetComputername "GetComputerNameA" kernel32.dll pointer sBuffer pointer lSize returns integer\r
+external_function WNetGetUser "WNetGetUserA" MPR.dll pointer lpName pointer lpUserName string  lpnLength returns DWord\r
+external_function SHBrowseForFolder "SHBrowseForFolder" shell32.dll pointer lpsBrowseInfo returns dword\r
+external_function SHGetPathFromIDList "SHGetPathFromIDList" shell32.dll pointer pidList pointer lpBuffer returns dWord\r
+external_function CoTaskMemFree "CoTaskMemFree" ole32.dll pointer pV returns integer\r
+external_function GetPID "_getpid" msvcrt.dll returns integer\r
+external_function getShortPathName "GetShortPathNameA" kernel32.dll pointer lpszLongPath pointer lpszShortPath integer cchBuffer returns integer\r
+external_function SetConsoleTitle "SetConsoleTitleA" Kernel32.dll string lpszTitle returns integer\r
+external_function FindWindow "FindWindowA" user32.dll pointer lpszClassName string lpszWindowName returns handle\r
+external_function GetSystemMenu "GetSystemMenu" user32.dll handle hwnd dword bRevert returns dword\r
+external_function EnableMenuItem "EnableMenuItem" user32.dll handle hmenu integer uIDEnableItem integer uEnable returns integer\r
+external_function ShellExecute "ShellExecuteA" shell32.dll handle hWnd pointer lpOperation pointer lpFile pointer lpParameters pointer lpDirectory integer nShowCmd returns integer\r
+external_function CreateProcess "CreateProcessA" kernel32.dll pointer lpAN pointer lpCL pointer lpPA pointer lpTA integer bIH dword dwCF pointer lpE pointer lpCD pointer lpSI pointer lpPi returns integer\r
+external_function OpenProcess "OpenProcess" kernel32.dll dword dwDesiredAccessas integer bInheritHandle dword dwProcId returns handle\r
+external_function TerminateProcess "TerminateProcess" kernel32.dll handle hProcess integer uExitCode returns integer\r
+external_function CloseHandle "CloseHandle" kernel32.dll handle hObject returns integer\r
+external_function WaitForSingleObject "WaitForSingleObject" kernel32.dll handle hHandle dword dwMilliseconds returns integer\r
+external_function32 Message_Beep "MessageBeep" user32.dll integer iSound returns integer\r
+external_function32 ExitWindowsEx "ExitWindowsEx" user32.dll integer uFlags integer dwReserved returns integer\r
+external_function lOpen "_lopen" kernel32.dll string lpPathName integer iReadWrite returns integer\r
+external_function lClose "_lclose" kernel32.dll handle hFile returns integer\r
+external_function GetLastError "GetLastError" kernel32.dll returns integer\r
+external_function CreateFile "CreateFileA" kernel32.dll pointer lpFNname dword dwDAccess dword dwSMode pointer lpSecAttrib dword dwCreationDisp dword dwFlagsAndAttrib handle hTemplateFile returns handle\r
+external_function GetFileSize "GetFileSize" kernel32.dll handle hFile pointer lpFileSizeHigh returns integer\r
+external_function SetFilePointer "SetFilePointer" kernel32.dll handle hFile dword lDistanceToMove pointer lpDistanceToMoveHigh dword dwMoveMethod returns handle\r
+external_function ReadFile "ReadFile" kernel32.dll handle hFile pointer lpBuffer integer nNumberOfBytesToRead pointer lpNumberOfBytesRead pointer lpOverlapped returns integer\r
+external_function CopyMemory "RtlMoveMemory" kernel32.dll pointer pDst pointer pSrc integer byteLen returns integer\r
+external_function EnumProcesses "EnumProcesses" psapi.dll pointer lpidProcess integer cb pointer cbNeeded returns integer\r
+external_function EnumProcessModules "EnumProcessModules" psapi.dll  handle hProcess pointer lphModule integer cb integer cbNeeded returns integer\r
+external_function WideCharToMultiByte "WideCharToMultiByte" kernel32.dll integer cp dword dwF pointer lpWCS integer cchWC pointer lpMBS integer cchMB string dC string uDC returns integer\r
+external_function GetSystemTime "GetSystemTime" kernel32.dll Pointer lpGST returns VOID_TYPE\r
+external_function GetTickCount "GetTickCount" kernel32.dll returns dWord\r
+external_function32 CoCreateGuid "CoCreateGuid" ole32.dll pointer pGUIDStructure returns word\r
+external_function32 StringFromGUID2 "StringFromGUID2" ole32.dll pointer pGUIDStructure pointer lpstrClsId integer cbMax returns dword\r
+external_function MsiQueryProductState "MsiQueryProductStateA" msi.dll string szProduct returns integer\r
+external_function MilliSleep "Sleep" kernel32.dll integer dwMilliseconds returns integer\r
+external_function SetLastError "SetLastError" kernel32.dll dword dwErrCode returns integer\r
+external_function FormatMessage "FormatMessageA" kernel32.dll integer dwFlags pointer lpSource dword dwMessageId dword dwLanguageId pointer lpBuffer integer nSize dword Arguments returns integer\r
+external_function GetProcessMemoryInfo "GetProcessMemoryInfo" PSAPI.DLL dword l_hProcess pointer ppsmemCounters dword cb returns integer\r
+external_function MultiByteToWideChar "MultiByteToWideChar" kernel32.dll integer cp dword dwF pointer lpWCS integer cchWC pointer lpMBS integer cchMB string dC string uDC returns integer\r
+external_function GetDiskFreeSpace "GetDiskFreeSpaceA" kernel32.dll string lpRootPathName pointer lpSectorsPC pointer lpBytesPS pointer lpNumberOfFreeClusters pointer lpTotalNOC returns integer\r
+external_function InternetCanonicalizeUrl "InternetCanonicalizeUrlA" wininet.dll pointer lpszUrl pointer lpszBuffer pointer lpdwBufferLength dword dwFlags returns integer\r
+external_function CryptAcquireContext "CryptAcquireContextA" advapi32.dll pointer phProv string pszContainer string pszProvider dword dwProvType dword dwFlags returns integer\r
+external_function CryptReleaseContext "CryptReleaseContext" advapi32.dll pointer phProv dword dwFlags returns integer\r
+external_function CryptCreateHash "CryptCreateHash" advapi32.dll handle hProv dword Algid handle hKey dword dwFlags pointer phHash returns integer\r
+external_function CryptDestroyHash "CryptDestroyHash" advapi32.dll handle hHash returns integer\r
+external_function CryptHashData "CryptHashData" advapi32.dll handle hHash pointer pbData dword dwDataLen dword dwFlags returns integer\r
+external_function CryptGetHashParam "CryptGetHashParam" advapi32.dll handle hHash dword dwParam pointer pbData pointer pdwDataLen dword dwFlags returns integer\r
+external_function CryptEnumProviders "CryptEnumProvidersA" advapi32.dll dword dwIndex pointer pdwReserved dword dwFlags pointer pdwProvType pointer pcbProvName pointer pszProvName returns integer\r
+external_function CryptBinaryToString "CryptBinaryToStringA" crypt32.dll dword pbBinary dword cbBinary dword dwFlags pointer pszString pointer pcchString returns integer\r
+external_function CryptGetProvParam "CryptGetProvParam" advapi32.dll handle hProv dword dwParam pointer pbData pointer pdwDataLen dword dwFlags returns integer\r
+external_function CryptContextAddRef "CryptGetProvParam" advapi32.dll handle hProv dword pdwReserved dword dwFlags returns integer\r
+external_function CryptImportKey "CryptImportKey" advapi32.dll handle hProv pointer pbData pointer pdwDataLen dword hPubKey dword dwFlags pointer phKey returns integer\r
+external_function CryptExportKey "CryptExportKey" advapi32.dll handle hKey handle hExpKey dword dwBlobType dword dwFlags pointer pbData pointer pdwDataLen returns integer\r
+external_function CryptDeriveKey "CryptDeriveKey" advapi32.dll handle hProv dword Algid handle hHash dword dwFlags pointer phKey returns integer\r
+external_function CryptDestroyKey "CryptDestroyKey" advapi32.dll handle hKey returns integer\r
+external_function CryptEncrypt "CryptEncrypt" advapi32.dll handle hKey handle hHash dword bFinal dword dwFlags pointer pbData pointer pdwDataLen dword dwBufLen returns integer\r
+external_function CryptDecrypt "CryptDecrypt" advapi32.dll handle hKey handle hHash dword bFinal dword dwFlags pointer pbData pointer pdwDataLen returns integer\r
+external_function CryptSetKeyParam "CryptSetKeyParam" advapi32.dll handle hKey dword dwParam pointer pbData dword dwFlags returns integer\r
+external_function CryptBinaryToString "CryptBinaryToStringA" crypt32.dll dword pbBinary dword cbBinary dword dwFlags pointer pszString pointer pcchString returns integer\r
+external_function CryptStringToBinary "CryptStringToBinaryA" crypt32.dll pointer pszString dword cchString dword dwFlags pointer pbBinary pointer pcbBinary pointer pdwSkip pointer pdwFlags returns integer\r
+external_function GetVersionEx "GetVersionExA" kernel32.dll pointer lpVersionInfo returns integer\r
+external_function GetSystemTime "GetSystemTime" kernel32.dll pointer lpSystemTime returns integer\r
+external_function GetTimeZoneInformation "GetTimeZoneInformation" kernel32.dll pointer lpTimeZoneInformation returns integer\r
+external_function GetTzi "GetTzi" timezone.dll pointer lpTimeZone pointer lpResult returns integer\r
+\r
+//-------------------------------------------------------------------------\r
+// Constants\r
+//-------------------------------------------------------------------------\r
+\r
+// MSI Constants\r
+#REPLACE INSTALLSTATE_UNKNOWN               |CI$-0000001   // No action to be taken on the feature or component.\r
+#REPLACE INSTALLSTATE_BROKEN                |CI$00000000   // The feature is broken\r
+#REPLACE INSTALLSTATE_ADVERTISED            |CI$00000001   //  Advertised feature\r
+#REPLACE INSTALLSTATE_ABSENT                |CI$00000002   //  The feature is not installed.\r
+#REPLACE INSTALLSTATE_LOCAL                 |CI$00000003   //  The feature is installed locally.\r
+#REPLACE INSTALLSTATE_DEFAULT               |CI$00000005   //  The product is to be installed with all features installed to the default states specified in the Feature table.\r
+\r
+// MCI Constants\r
+#REPLACE SIMPLE_BEEP                        |CI$-0000001    // SimpleBeep = -1,\r
+#REPLACE WINMDOWS_OK                        |CI$00000000    // A standard windows OK beep = 0x00,\r
+#REPLACE WINDOWS_QUESTION                   |CI$00000020    // A standard windows Question beep = 0x20,\r
+#REPLACE WINDOWS_EXCLAMATION                |CI$00000030    // A standard windows Exclamation beep = 0x30,\r
+#REPLACE WINDOWS_ASTERISK                   |CI$00000040    // A standard windows Asterisk beep = 0x40,\r
+\r
+// ExitWindowsEx Constants\r
+#REPLACE EWX_LOGOFF                         |CI$00000000    // logoff\r
+#REPLACE EWX_SHUTDOWN                       |CI$00000001    // shutdown\r
+#REPLACE EWX_REBOOT                         |CI$00000002    // Reboot\r
+#REPLACE EWX_FORCE                          |CI$00000004    // Force shutdown\r
+\r
+// SHFileOperation Constants\r
+#REPLACE MaxDword                           |CI$FFFFFFFF\r
+#REPLACE FO_COPY                            |CI$00000002    //  FO_COPY              &H2     Copies a file or folder\r
+#REPLACE FO_DELETE                          |CI$00000003    //  FO_DELETE            &H3     Deletes a file or folder\r
+#REPLACE FO_MOVE                            |CI$00000001    //  FO_MOVE              &H1     Moves a file or folder\r
+#REPLACE FO_RENAME                          |CI$00000004    //  FO_RENAME            &H4     Renames a file or folder\r
+#REPLACE FOF_ALLOWUNDO                      |CI$00000040    //  FOF_ALLOWUNDO        &H40    Used with Rename. When used with Delete the files get sent to the Recycle Bin.\r
+#REPLACE FOF_FILESONLY                      |CI$00000080    //  FOF_FILESONLY        &H80    Only allows files.\r
+#REPLACE FOF_NOCONFIRMATION                 |CI$00000010    //  FOF_NOCONFIRMATION   &H10    Does not display the Delete or Overwrite confirmation dialog.\r
+#REPLACE FOF_SILENT                         |CI$00000004    //  FOF_SILENT           &H4     Does not display the Windows animation while performing the opperation.\r
+#REPLACE FOF_SIMPLEPROGRESS                 |CI$00000100    //  FOF_SIMPLEPROGRESS   &H100   Does not display filenames.\r
+#REPLACE FOF_NOCOPYSECURITYATTRIBS          |CI$00000800    //  Do not copy NT file Security Attributes\r
+#REPLACE FOF_NOERRORUI                      |CI$00000400    //  Do not display a dialog to the user if an error occurs.\r
+#REPLACE FOF_NOCONFIRMMKDIR                 |CI$00000200    //  Do not ask the user to confirm the creation of a new directory if the operation requires one to be created\r
+\r
+// FolderBrowse Constants\r
+#REPLACE BIF_RETURNONLYFSDIRS               |CI$00000001    // Window will only return when user selects a filesystem folder\r
+#REPLACE BIF_DONTGOBELOWDOMAIN              |CI$00000002    // Do not include network folders below the domain level\r
+#REPLACE BIF_STATUSTEXT                     |CI$00000004    // Sets the window label to the chosen folder\r
+#REPLACE BIF_RETURNFSANCESTORS              |CI$00000008    // Only return file system directories.\r
+#REPLACE BIF_EDITBOX                        |CI$00000010    // Show edit, so user can edit path\r
+#REPLACE BIF_BROWSEFORCOMPUTER              |CI$00001000    // Only return computers\r
+#REPLACE BIF_BROWSEFORPRINTER               |CI$00002000    // Only return printers\r
+#REPLACE BIF_BROWSEINCLUDEFILES             |CI$00004000    // Display files as well as folders\r
+\r
+// GDI Window Constants\r
+#REPLACE SC_CLOSE                           |CI$0000F060\r
+#REPLACE MF_BYCOMMAND                       |CI1\r
+#REPLACE MF_ENABLED                         |CI0\r
+#REPLACE MF_GRAYED                          |CI1\r
+\r
+// ShellExecute Constants\r
+#REPLACE SW_HIDE                            |CI00       // Hides the window and activates another window;\r
+#REPLACE SW_MAXIMIZE                        |CI01       // Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.\r
+#REPLACE SW_MINIMIZE                        |CI02       // Minimizes the specified window and activates the next top-level window in the Z order\r
+#REPLACE SW_RESTORE                         |CI03       // Maximizes the specified window\r
+#REPLACE SW_SHOW                            |CI04       // Displays a window in its most recent size and position. The active window remains active.\r
+#REPLACE SW_SHOWDEFAULT                     |CI05       // Activates the window and displays it in its current size and position\r
+#REPLACE SW_SHOWMAXIMIZED                   |CI06       // Minimizes the specified window and activates the next top-level window in the Z order\r
+#REPLACE SW_SHOWMINIMIZED                   |CI07       // Displays the window as a minimized window. The active window remains active\r
+#REPLACE SW_SHOWMINNOACTIVE                 |CI08       // Displays the window in its current state. The active window remains active\r
+#REPLACE SW_SHOWNA                          |CI09       // Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.\r
+#REPLACE SW_SHOWNOACTIVATE                  |CI10       // Displays a window in its most recent size and position. The active window remains active.\r
+#REPLACE SW_SHOWNORMAL                      |CI11       // Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.\r
+\r
+// CreateProcess constants\r
+#REPLACE SYNCHRONIZE                        |CI1048576\r
+#REPLACE NORMAL_PRIORITY_CLASS              |CI$00000020\r
+#REPLACE HEXNULL                            |CI$00000000\r
+#REPLACE HEXTRUE                            |CI$00000001\r
+#REPLACE STRINGNULL                         |CS''\r
+#REPLACE INFINITE                           |CI$-0000001    // Wait until process terminates\r
+\r
+#REPLACE CREATE_NEW_CONSOLE                 |CI$00000010    // The new process has a new console, instead of inheriting the parent's console.\r
+#REPLACE CREATE_NEW_PROCESS_GROUP           |CI$00000200    // Not supported.\r
+#REPLACE CREATE_SEPARATE_WOW_VDM            |CI$00000800    // Not supported.\r
+#REPLACE CREATE_SHARED_WOW_VDM              |CI$00001000    // Not supported.\r
+#REPLACE CREATE_SUSPENDED                   |CI$00000004    // The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.\r
+#REPLACE CREATE_UNICODE_ENVIRONMENT         |CI000000400    // Not supported.\r
+#REPLACE DEBUG_PROCESS                      |CI$00000001    // If this flag is set, the calling process is treated as a debugger, and the new process is a process being debugged. Child processes of the new process are also debugged.\r
+                                                            // The system notifies the debugger of all debug events that occur in the process being debugged.\r
+                                                            // If you create a process with this flag set, only the calling thread (the thread that called CreateProcess) can call the WaitForDebugEvent function.\r
+#REPLACE DEBUG_ONLY_THIS_PROCESS            |CI$00000002    // If this flag is set, the calling process is treated as a debugger, and the new process is a process being debugged. No child processes of the new process are debugged.\r
+                                                            // The system notifies the debugger of all debug events that occur in the process being debugged.\r
+#REPLACE DETACHED_PROCESS                   |CI$00000008    // Not supported.\r
+#REPLACE INHERIT_CALLER_PRIORITY            |CI$00020000    // If this flag is set, the new process inherits the priority of the creator process.\r
+#REPLACE REALTIME_PRIORITY_CLASS            |CI000000100\r
+#REPLACE HIGH_PRIORITY_CLASS                |CI$00000080\r
+#REPLACE IDLE_PRIORITY_CLASS                |CI$00000040\r
+\r
+// Readmode Constants\r
+#REPLACE OF_READ                            |CI$00000000\r
+#REPLACE OF_WRITE                           |CI$00000001\r
+#REPLACE OF_READWRITE                       |CI$00000002\r
+\r
+// Attribute Constants\r
+#REPLACE FILE_ATTRIBUTE_READONLY            |CI$00000001\r
+#REPLACE FILE_ATTRIBUTE_HIDDEN              |CI$00000002\r
+#REPLACE FILE_ATTRIBUTE_SYSTEM              |CI$00000004\r
+#REPLACE FILE_ATTRIBUTE_DIRECTORY           |CI$00000010\r
+#REPLACE FILE_ATTRIBUTE_ARCHIVE             |CI$00000020\r
+#REPLACE FILE_ATTRIBUTE_NORMAL              |CI$00000080\r
+#REPLACE FILE_ATTRIBUTE_TEMPORARY           |CI$00000100\r
+#REPLACE FILE_ATTRIBUTE_ENCRYPTED           |CI$00000040  //  NT, Windows 2000 only\r
+#REPLACE FILE_ATTRIBUTE_OFFLINE             |CI$00001000  //  Windows 2000 only\r
+#REPLACE FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |CI$00002000  //  NT, Windows 2000 only\r
+\r
+// Sharemode Constants\r
+#REPLACE OF_SHARE_COMPAT                    |CI$00000000\r
+#REPLACE OF_SHARE_EXCLUSIVE                 |CI$00000010\r
+#REPLACE OF_SHARE_DENY_WRITE                |CI$00000020\r
+#REPLACE OF_SHARE_DENY_READ                 |CI$00000030\r
+#REPLACE OF_SHARE_DENY_NONE                 |CI$00000040\r
+#REPLACE OF_PARSE                           |CI$00000100\r
+#REPLACE OF_DELETE                          |CI$00000200\r
+#REPLACE OF_VERIFY                          |CI$00000400\r
+#REPLACE OF_CANCEL                          |CI$00000800\r
+#REPLACE OF_CREATE                          |CI$00001000\r
+#REPLACE OF_PROMPT                          |CI$00002000\r
+#REPLACE OF_EXIST                           |CI$00004000\r
+#REPLACE OF_REOPEN                          |CI$00008000\r
+\r
+// Accessmode Constants\r
+#REPLACE FILE_SHARE_DELETE                  |CI$00000000\r
+#REPLACE FILE_SHARE_READ                    |CI$00000001\r
+#REPLACE FILE_SHARE_WRITE                   |CI$00000002\r
+#REPLACE FILE_BEGIN                         |CI0\r
+#REPLACE FILE_CURRENT                       |CI1\r
+#REPLACE FILE_END                           |CI2\r
+#REPLACE OPEN_EXISTING                      |CI3\r
+#REPLACE OPEN_ALWAYS                        |CI4\r
+#REPLACE TRUNCATE_EXISTING                  |CI5\r
+#REPLACE GENERIC_READ                       |CI$80000000\r
+#REPLACE GENERIC_WRITE                      |CI$40000000\r
+\r
+// file handle\r
+#REPLACE INVALID_HANDLE_VALUE               |CI-00000001\r
+\r
+// dwFlags Constants\r
+#REPLACE WC_NO_BEST_FIT_CHARS               |CI$00000400\r
+#REPLACE WC_COMPOSITECHECK                  |CI$00000200\r
+#REPLACE WC_DISCARDNS                       |CI$00000010\r
+#REPLACE WC_SEPCHARS                        |CI$00000020\r
+#REPLACE WC_DEFAULTCHAR                     |CI$00000040\r
+#REPLACE WC_ERR_INVALID_CHARS               |CI$00000080 // Vista onwards only\r
+\r
+// Codepage Constants\r
+#REPLACE CP_ACP                             |CI0\r
+#REPLACE CP_OEMCP                           |CI1\r
+#REPLACE CP_MACCP                           |CI2\r
+#REPLACE CP_UTF7                            |CI65000\r
+#REPLACE CP_UTF8                            |CI65001\r
+\r
+// Running Process Constants\r
+#REPLACE PROCESS_QUERY_INFORMATION_X        |CI$00001024\r
+#REPLACE PROCESS_QUERY_INFORMATION          |CI$00000400\r
+#REPLACE PROCESS_VM_READ_X                  |CI$00000016\r
+#REPLACE PROCESS_VM_READ                    |CI$00000010\r
+#REPLACE STANDARD_RIGHTS_REQUIRED           |CI$FFFF0000\r
+\r
+\r
+// GUID Constants\r
+#REPLACE GUID_STRING_LENGTH                 |CI$00000050       // GUID Length\r
+\r
+// FormatMessage\r
+#REPLACE FORMAT_MESSAGE_ALLOCATE_BUFFER     |CI$00000100\r
+#REPLACE FORMAT_MESSAGE_FROM_SYSTEM         |CI$00001000\r
+#REPLACE LANG_NEUTRAL                       |CI$00000000\r
+#REPLACE SUBLANG_DEFAULT                    |CI$00000001\r
+#REPLACE ERROR_BAD_USERNAME                 |CI$00002202\r
+\r
+// InternetCanonicalizeUrl\r
+#REPLACE ICU_NO_ENCODE                      |CI$20000000        // Don't convert unsafe characters to escape sequence\r
+#REPLACE ICU_DECODE                         |CI$10000000        // Convert %XX escape sequences to characters\r
+#REPLACE ICU_NO_META                        |CI$08000000        // Don't convert .. etc. meta path sequences\r
+#REPLACE ICU_ENCODE_SPACES_ONLY             |CI$04000000        // Encode spaces only\r
+#REPLACE ICU_BROWSER_MODE                   |CI$02000000        // Special encode/decode rules for browser\r
+\r
+// advapi32 Crypt* constants\r
+#REPLACE PROV_RSA_FULL                      |CI00000001\r
+#REPLACE PROV_RSA_SIG                       |CI00000002\r
+#REPLACE PROV_DSS                           |CI00000003\r
+#REPLACE PROV_FORTEZZA                      |CI00000004\r
+#REPLACE PROV_MS_EXCHANGE                   |CI00000005\r
+#REPLACE PROV_SSL                           |CI00000006\r
+#REPLACE PROV_RSA_SCHANNEL                  |CI00000012\r
+#REPLACE PROV_DSS_DH                        |CI00000013\r
+#REPLACE PROV_EC_ECDSA_SIG                  |CI00000014\r
+#REPLACE PROV_EC_ECNRA_SIG                  |CI00000015\r
+#REPLACE PROV_EC_ECDSA_FULL                 |CI00000016\r
+#REPLACE PROV_EC_ECNRA_FULL                 |CI00000017\r
+#REPLACE PROV_DH_SCHANNEL                   |CI00000018\r
+#REPLACE PROV_SPYRUS_LYNKS                  |CI00000020\r
+#REPLACE PROV_RNG                           |CI00000021\r
+#REPLACE PROV_INTEL_SEC                     |CI00000022\r
+#REPLACE PROV_REPLACE_OWF                   |CI00000023\r
+#REPLACE PROV_RSA_AES                       |CI00000024\r
+\r
+#REPLACE CRYPT_VERIFYCONTEXT                |CI00000000         // Supposedly |CI$F0000000\r
+#REPLACE CRYPT_NEWKEYSET                    |CI00000008\r
+#REPLACE CRYPT_DELETEKEYSET                 |CI00000016\r
+#REPLACE CRYPT_MACHINE_KEYSET               |CI00000032\r
+#REPLACE CRYPT_SILENT                       |CI00000064\r
+#REPLACE CRYPT_EXPORTABLE                   |CI00000001\r
+#REPLACE CRYPT_USER_PROTECTED               |CI00000002\r
+#REPLACE CRYPT_CREATE_SALT                  |CI00000004\r
+#REPLACE CRYPT_UPDATE_KEY                   |CI00000008\r
+\r
+#REPLACE CALG_3DES                          |CI$00006603    // Triple DES encryption algorithm.\r
+#REPLACE CALG_3DES_112                      |CI$00006609    // Two-key triple DES encryption with effective key length equal to 112 bits.\r
+#REPLACE CALG_AES                           |CI$00006611    // Advanced Encryption Standard (AES). This algorithm is supported by the Microsoft AES Cryptographic Provider.\r
+#REPLACE CALG_AES_128                       |CI$0000660E    // 128 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider.\r
+#REPLACE CALG_AES_192                       |CI$0000660F    // 192 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider.\r
+#REPLACE CALG_AES_256                       |CI$00006610    // 256 bit AES. This algorithm is supported by the Microsoft AES Cryptographic Provider.\r
+#REPLACE CALG_AGREEDKEY_ANY                 |CI$0000AA03    // Temporary algorithm identifier for handles of Diffie-Hellman-agreed keys.\r
+#REPLACE CALG_CYLINK_MEK                    |CI$0000660C    // An algorithm to create a 40-bit DES key that has parity bits and zeroed key bits to make its key length 64 bits. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_DES                           |CI$00006601    // DES encryption algorithm.\r
+#REPLACE CALG_DESX                          |CI$00006604    // DESX encryption algorithm.\r
+#REPLACE CALG_DH_EPHEM                      |CI$0000AA02    // Diffie-Hellman ephemeral key exchange algorithm.\r
+#REPLACE CALG_DH_SF                         |CI$0000AA01    // Diffie-Hellman store and forward key exchange algorithm.\r
+#REPLACE CALG_DSS_SIGN                      |CI$00002200    // DSA public key signature algorithm.\r
+#REPLACE CALG_ECDH                          |CI$0000AA05    // Elliptic curve Diffie-Hellman key exchange algorithm.\r
+#REPLACE CALG_ECDSA                         |CI$00002203    // Elliptic curve digital signature algorithm.\r
+#REPLACE CALG_ECMQV                         |CI$0000A001    // Elliptic curve Menezes, Qu, and Vanstone (MQV) key exchange algorithm. This algorithm is not supported.\r
+#REPLACE CALG_HASH_REPLACE_OWF              |CI$0000800B    // One way function hashing algorithm.\r
+#REPLACE CALG_HUGHES_MD5                    |CI$0000A003    // Hughes MD5 hashing algorithm.\r
+#REPLACE CALG_HMAC                          |CI$00008009    // HMAC keyed hash algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_KEA_KEYX                      |CI$0000AA04    // KEA key exchange algorithm (FORTEZZA). This algorithm is not supported.\r
+#REPLACE CALG_MAC                           |CI$00008005    // MAC keyed hash algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_MD2                           |CI$00008001    // MD2 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_MD4                           |CI$00008002    // MD4 hashing algorithm.\r
+#REPLACE CALG_MD5                           |CI$00008003    // MD5 hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_NO_SIGN                       |CI$00002000    // No signature algorithm.\r
+#REPLACE CALG_OID_INFO_CNG_ONLY             |CI$FFFFFFFF    // The algorithm is only implemented in CNG. The macro, IS_SPECIAL_OID_INFO_ALGID, can be used to determine whether a cryptography algorithm is only supported by using the CNG functions.\r
+#REPLACE CALG_OID_INFO_PARAMETERS           |CI$FFFFFFFE    // The algorithm is defined in the encoded parameters. The algorithm is only supported by using CNG. The macro, IS_SPECIAL_OID_INFO_ALGID, can be used to determine whether a cryptography algorithm is only supported by using the CNG functions.\r
+#REPLACE CALG_PCT1_MASTER                   |CI$00004C04    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_RC2                           |CI$00006602    // RC2 block encryption algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_RC4                           |CI$00006801    // RC4 stream encryption algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_RC5                           |CI$0000660D    // RC5 block encryption algorithm.\r
+#REPLACE CALG_RSA_KEYX                      |CI$0000A400    // RSA public key exchange algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_RSA_SIGN                      |CI$00002400    // RSA public key signature algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_SCHANNEL_ENC_KEY              |CI$00004C07    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_SCHANNEL_MAC_KEY              |CI$00004C03    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_SCHANNEL_MASTER_HASH          |CI$00004C02    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_SEAL                          |CI$00006802    // SEAL encryption algorithm. This algorithm is not supported.\r
+#REPLACE CALG_SHA                           |CI$00008004    // SHA hashing algorithm. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_SHA1                          |CI$00008004    // Same as CALG_SHA. This algorithm is supported by the Microsoft Base Cryptographic Provider.\r
+#REPLACE CALG_SHA_256                       |CI$0000800C    // 256 bit SHA hashing algorithm. This algorithm is supported by Microsoft Enhanced RSA and AES Cryptographic Provider..\r
+#REPLACE CALG_SHA_384                       |CI$0000800D    // 384 bit SHA hashing algorithm. This algorithm is supported by Microsoft Enhanced RSA and AES Cryptographic Provider.\r
+#REPLACE CALG_SHA_512                       |CI$0000800E    // 512 bit SHA hashing algorithm. This algorithm is supported by Microsoft Enhanced RSA and AES Cryptographic Provider.\r
+#REPLACE CALG_SKIPJACK                      |CI$0000660A    // Skipjack block encryption algorithm (FORTEZZA). This algorithm is not supported.\r
+#REPLACE CALG_SSL2_MASTER                   |CI$00004C05    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_SSL3_MASTER                   |CI$00004C01    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_SSL3_SHAMD5                   |CI$00008008    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_TEK                           |CI$0000660B    // TEK (FORTEZZA). This algorithm is not supported.\r
+#REPLACE CALG_TLS1_MASTER                   |CI$00004C06    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+#REPLACE CALG_TLS1PRF                       |CI$0000800A    // Used by the Schannel.dll operations system. This ALG_ID should not be used by applications.\r
+\r
+#REPLACE HP_ALGID                           |CI00000001\r
+#REPLACE HP_HASHVAL                         |CI00000002\r
+#REPLACE HP_HASHSIZE                        |CI00000004\r
+\r
+#REPLACE MS_ENH_RSA_AES_PROV_XP             "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"\r
+#REPLACE MS_ENH_RSA_AES_PROV                "Microsoft Enhanced RSA and AES Cryptographic Provider"\r
+#REPLACE MS_DEF_PROV                        "Microsoft Base Cryptographic Provider v1.0"\r
+\r
+#REPLACE PP_ADMIN_PIN                       |CI$0000001F  // Returns the administrator personal identification number (PIN) in the pbData parameter as a LPSTR.\r
+#REPLACE PP_CERTCHAIN                       |CI$00000009  // Returns the certificate chain associated with the hProv handle. The returned certificate chain is \r
+                                                          // X509_ASN_ENCODING encoded.\r
+#REPLACE PP_CONTAINER                       |CI$00000006  // The name of the current key container as a null-terminated CHAR string. \r
+                                                          // This string is exactly the same as the one passed in the pszContainer \r
+                                                          // parameter of the CryptAcquireContext function to specify the key \r
+                                                          // container to use. The pszContainer parameter can be read to determine \r
+                                                          // the name of the default key container.\r
+#REPLACE PP_ENUMALGS                        |CI$00000001  // A PROV_ENUMALGS structure that contains information about one algorithm supported by the CSP being queried.\r
+#REPLACE PP_ENUMALGS_EX                     |CI$00000016  // A PROV_ENUMALGS_EX structure that contains information about one algorithm supported by the CSP being queried. \r
+                                                          // The structure returned contains more information about the algorithm than the structure returned for PP_ENUMALGS.\r
+#REPLACE PP_ENUMCONTAINERS                  |CI$00000002  // The name of one of the key containers maintained by the CSP in the form of a null-terminated CHAR string. \r
+#REPLACE PP_ENUMEX_SIGNING_PROT             |CI$00000028  // Indicates that the current CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. \r
+                                                          // If this function succeeds, the CSP supports the dwProtocols member of the PROV_ENUMALGS_EX structure. \r
+                                                          // If this function fails with an NTE_BAD_TYPE error code, the CSP does not support the dwProtocols member.\r
+#REPLACE PP_IMPTYPE                         |CI$00000003  // A DWORD value that indicates how the CSP is implemented. For a table of possible values, see Remarks.\r
+#REPLACE PP_KEYEXCHANGE_PIN                 |CI$00000020  // Specifies that the key exchange PIN is contained in pbData. The PIN is represented as a null-terminated ASCII string.\r
+#REPLACE PP_KEYSET_SEC_DESCR                |CI$00000008  // Retrieves the security descriptor for the key storage container. The pbData parameter is the address of a \r
+                                                          // SECURITY_DESCRIPTOR structure that receives the security descriptor for the key storage container. \r
+                                                          // The security descriptor is returned in self-relative format.\r
+#REPLACE PP_NAME                            |CI$00000004  // The name of the CSP in the form of a null-terminated CHAR string. This string is identical to the one passed in \r
+                                                          // the pszProvider parameter of the CryptAcquireContext function to specify that the current CSP be used.\r
+\r
+// Encryption key formats\r
+#REPLACE PUBLICKEYBLOB                      |CI$00000006\r
+#REPLACE PRIVATEKEYBLOB                     |CI$00000007\r
+#REPLACE PLAINTEXTKEYBLOB                   |CI$00000008\r
+\r
+// Key params for advapi32 cryptography dwParam\r
+#REPLACE KP_IV                              |CI1         // Initialization vector\r
+#REPLACE KP_SALT                            |CI2         // Salt value\r
+#REPLACE KP_PADDING                         |CI3         // Padding values\r
+#REPLACE KP_MODE                            |CI4         // Mode of the cipher\r
+#REPLACE KP_MODE_BITS                       |CI5         // Number of bits to feedback\r
+#REPLACE KP_PERMISSIONS                     |CI6         // Key permissions DWORD\r
+#REPLACE KP_ALGID                           |CI7         // Key algorithm\r
+#REPLACE KP_BLOCKLEN                        |CI8         // Block size of the cipher\r
+#REPLACE KP_KEYLEN                          |CI9         // Length of key in bits\r
+#REPLACE KP_SALT_EX                         |CI10        // Length of salt in bytes\r
+#REPLACE KP_P                               |CI11        // DSS/Diffie-Hellman P value\r
+#REPLACE KP_G                               |CI12        // DSS/Diffie-Hellman G value\r
+#REPLACE KP_Q                               |CI13        // DSS Q value\r
+#REPLACE KP_X                               |CI14        // Diffie-Hellman X value\r
+#REPLACE KP_Y                               |CI15        // Y value\r
+#REPLACE KP_RA                              |CI16        // Fortezza RA value\r
+#REPLACE KP_RB                              |CI17        // Fortezza RB value\r
+#REPLACE KP_INFO                            |CI18        // For putting information into an RSA envelope\r
+#REPLACE KP_EFFECTIVE_KEYLEN                |CI19        // Setting and getting RC2 effective key length\r
+#REPLACE KP_SCHANNEL_ALG                    |CI20        // for setting the Secure Channel algorithms\r
+#REPLACE KP_CLIENT_RANDOM                   |CI21        // for setting the Secure Channel client random data\r
+#REPLACE KP_SERVER_RANDOM                   |CI22        // for setting the Secure Channel server random data\r
+#REPLACE KP_RP                              |CI23\r
+#REPLACE KP_PRECOMP_MD5                     |CI24\r
+#REPLACE KP_PRECOMP_SHA                     |CI25\r
+#REPLACE KP_CERTIFICATE                     |CI26        // for setting Secure Channel certificate data (PCT1)\r
+#REPLACE KP_CLEAR_KEY                       |CI27        // for setting Secure Channel clear key data (PCT1)\r
+#REPLACE KP_PUB_EX_LEN                      |CI28\r
+#REPLACE KP_PUB_EX_VAL                      |CI29\r
+#REPLACE KP_KEYVAL                          |CI30\r
+#REPLACE KP_ADMIN_PIN                       |CI31\r
+#REPLACE KP_KEYEXCHANGE_PIN                 |CI32\r
+#REPLACE KP_SIGNATURE_PIN                   |CI33\r
+#REPLACE KP_PREHASH                         |CI34 \r
+#REPLACE KP_OAEP_PARAMS                     |CI36        // for setting OAEP params on RSA keys\r
+#REPLACE KP_CMS_KEY_INFO                    |CI37\r
+#REPLACE KP_CMS_DH_KEY_INFO                 |CI38\r
+#REPLACE KP_PUB_PARAMS                      |CI39        // for setting public parameters\r
+#REPLACE KP_VERIFY_PARAMS                   |CI40        // for verifying DSA and DH parameters\r
+#REPLACE KP_HIGHEST_VERSION                 |CI41        // for TLS protocol version setting \r
+\r
+// Key params for advapi32 cryptography KP_PADDING\r
+#REPLACE PKCS5_PADDING                       |CI1         // PKCS 5 (sec 6.2) padding method\r
+#REPLACE RANDOM_PADDING                      |CI2\r
+#REPLACE ZERO_PADDING                        |CI3 \r
+\r
+// Key params for advapi32 cryptography KP_MODE\r
+#REPLACE CRYPT_MODE_CBC                      |CI1         // Cipher block chaining\r
+#REPLACE CRYPT_MODE_ECB                      |CI2         // Electronic code book\r
+#REPLACE CRYPT_MODE_OFB                      |CI3         // Output feedback mode\r
+#REPLACE CRYPT_MODE_CFB                      |CI4         // Cipher feedback mode\r
+#REPLACE CRYPT_MODE_CTS                      |CI5         // Ciphertext stealing mode \r
+\r
+// Params for crypt32 hashing\r
+#REPLACE CRYPT_STRING_BASE64                |CI$00000001\r
+#REPLACE CRYPT_STRING_HEX                   |CI$00000004\r
+#REPLACE CRYPT_STRING_HEXASCII              |CI$00000005\r
+#REPLACE CRYPT_STRING_HEXADDR               |CI$0000000A\r
+#REPLACE CRYPT_STRING_HEXASCIIADDR          |CI$0000000B\r
+#REPLACE CRYPT_STRING_HEXRAW                |CI$0000000C\r
+\r
+// Used by out GetTimeZoneInformation / GetSystemTime\r
+#REPLACE TIME_ZONE_ID_UNKNOWN               |CI$00000000\r
+#REPLACE TIME_ZONE_ID_STANDARD              |CI$00000001\r
+#REPLACE TIME_ZONE_ID_DAYLIGHT              |CI$00000002\r
+#REPLACE TIME_ZONE_ID_INVALID               |CI$FFFFFFFF\r
+\r
+//-------------------------------------------------------------------------\r
+// Structs\r
+//-------------------------------------------------------------------------\r
+\r
+// Used by convert_date_format to convert two dword values representing file mod time into string\r
+type _FILETIME\r
+    field FILETIME.dwLowDateTime as dword\r
+    field FILETIME.dwHighDateTime as dword\r
+end_type\r
+\r
+// Used by convert_date_format to convert two dword values representing system time into string\r
+type _SYSTEMTIME\r
+    field SYSTEMTIME.wYear as word\r
+    field SYSTEMTIME.wMonth as word\r
+    field SYSTEMTIME.wDayOfWeek as word\r
+    field SYSTEMTIME.wDay as word\r
+    field SYSTEMTIME.wHour as word\r
+    field SYSTEMTIME.wMinute as word\r
+    field SYSTEMTIME.wSecond as word\r
+    field SYSTEMTIME.wMilliseconds as word\r
+end_type\r
+\r
+type _SYSTEMTIME2\r
+    field SYSTEMTIME2.wYear as char 2\r
+    field SYSTEMTIME2.wMonth as char 2\r
+    field SYSTEMTIME2.wDayOfWeek as char 2\r
+    field SYSTEMTIME2.wDay as char 2\r
+    field SYSTEMTIME2.wHour as char 2\r
+    field SYSTEMTIME2.wMinute as char 2\r
+    field SYSTEMTIME2.wSecond as char 2\r
+    field SYSTEMTIME2.wMilliseconds as char 2\r
+end_type\r
+\r
+// Used by list_directory to read data out of string returned by kernel32\r
+type _WIN32_FIND_DATA\r
+    field WIN32_FIND_DATA.dwFileAttributes as dword\r
+    field WIN32_FIND_DATA.ftCreationLowDateTime as dword\r
+    field WIN32_FIND_DATA.ftCreationHighDateTime as dword\r
+    field WIN32_FIND_DATA.ftLastAccessLowDateTime as dword\r
+    field WIN32_FIND_DATA.ftLastAccessHighDateTime As dword\r
+    field WIN32_FIND_DATA.ftLastWriteLowDateTime as dword\r
+    field WIN32_FIND_DATA.ftLastWriteHighDateTime as dword\r
+    field WIN32_FIND_DATA.nFileSizeHigh as dword\r
+    field WIN32_FIND_DATA.nFileSizeLow as dword\r
+    field WIN32_FIND_DATA.dwReserved0 as dword\r
+    field WIN32_FIND_DATA.dwReserved1 as dword\r
+    field WIN32_FIND_DATA.cFileName as char 260\r
+    field WIN32_FIND_DATA.cAlternateFileName as char 14\r
+end_type\r
+// used by fileopp to pass details into SHFileOperation\r
+type _SHFILEOPSTRUCT\r
+    field SHFileOpStruct.hWnd as dword // Handle of dialog box to display status info - think this is for vb c# etc\r
+    field SHFileOpStruct.wFunc as dword // Operation to perform\r
+    field SHFileOpStruct.pFrom as pointer // char // A string specifying one or more source file names. Multiple names must be null-separated. The list of names must be double null-terminated\r
+    field SHFileOpStruct.pTo as pointer // char // Same as pFrom except for the destination\r
+    field SHFileOpStruct.fFlags as integer // Flags that control the file operation\r
+    field SHFileOpStruct.fAnyOperationsAborted as dword // TRUE if an operation was aborted before it was completed\r
+    field SHFileOpStruct.hNameMappings as dword // Only used with certain flags\r
+    field SHFileOpStruct.lpszProgressTitle as dword // Title for a progress dialog box\r
+end_type\r
+\r
+// Used by getComputerName to read computer name out into\r
+type _SIZEGETCOMPUTERNAME\r
+    field SIZEGETCOMPUTERNAME.dwSize as dWord\r
+end_type\r
+\r
+// Used by folderbrowse to send parameters to and read data out from SHBrowseFolder\r
+type _BROWSEINFO\r
+    field BROWSEINFO.hWndOwner as handle\r
+    field BROWSEINFO.pIDLRoot as pointer\r
+    field BROWSEINFO.pszDisplayName as pointer\r
+    field BROWSEINFO.lpszTitle as pointer\r
+    field BROWSEINFO.ulFlags as dword\r
+    field BROWSEINFO.lpfnCallback as pointer\r
+    field BROWSEINFO.lParam as dword\r
+    field BROWSEINFO.iImage as dword\r
+end_type\r
+// Used by create_proc to read created process details out of kernel32\r
+type _PROCESS_INFORMATION\r
+    field PROCESS_INFORMATION.hProcess as handle\r
+    field PROCESS_INFORMATION.hThread as handle\r
+    field PROCESS_INFORMATION.dwProcessId as dword\r
+    field PROCESS_INFORMATION.dwThreadId as dword\r
+end_type\r
+// Used by create_proc to read create process details into of kernel32\r
+type _STARTUPINFO\r
+    field STARTUPINFO.cb as integer\r
+    field STARTUPINFO.lpReserved as pointer // to string\r
+    field STARTUPINFO.lpDesktop as pointer // to string\r
+    field STARTUPINFO.lpTitle as pointer // to string\r
+    field STARTUPINFO.dwX as dword\r
+    field STARTUPINFO.dwY as dword\r
+    field STARTUPINFO.dwXSize as dword\r
+    field STARTUPINFO.dwYSize as dword\r
+    field STARTUPINFO.dwXCountChars as dword\r
+    field STARTUPINFO.dwYCountChars as dword\r
+    field STARTUPINFO.dwFillAttribute as dword\r
+    field STARTUPINFO.dwFlags as dword\r
+    field STARTUPINFO.wShowWindow as integer\r
+    field STARTUPINFO.cbReserved2 as integer\r
+    field STARTUPINFO.lpReserved2 as pointer\r
+    field STARTUPINFO.hStdInput as handle\r
+    field STARTUPINFO.hStdOutput as handle\r
+    field STARTUPINFO.hStdError as handle\r
+end_type\r
+// Used to receive an array from get_procs\r
+type _PROCESSARRAY\r
+    field PROCESSARRAY.arrayItem as dword\r
+end_type\r
+\r
+// Used by ReadFile\r
+type _STRUCTBYTESREAD\r
+    field STRUCTBYTESREAD.integer0 as dword\r
+end_type\r
+// Used by get_procs\r
+type _STRUCTBYTESBACK\r
+    field STRUCTBYTESBACK.integer0 as dword\r
+end_type\r
+\r
+// Used by create_guid (http:// msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx)\r
+type _GUID\r
+    field GUID.data1 as dword\r
+    field GUID.data2 as word\r
+    field GUID.data3 as word\r
+    field GUID.data4 as char 8\r
+end_type\r
+\r
+type _DISKDATA1\r
+    field DISKDATA1.sectorsPerCluster as dword\r
+end_type\r
+type _DISKDATA2\r
+    field DISKDATA2.bytesPerSector as dword\r
+end_type\r
+type _DISKDATA3\r
+    field DISKDATA3.numberOfFreeClusters as dword\r
+end_type\r
+type _DISKDATA4\r
+    field DISKDATA4.totalNumberOfClusters as dword\r
+end_type\r
+\r
+// Used by GetProcessMemoryInfo\r
+type _PROCESS_MEMORY_COUNTERS\r
+    field PROCESS_MEMORY_COUNTERS.cb as dword               // The size of the structure, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.PageFaultCount as dword           // The number of page faults.\r
+    field PROCESS_MEMORY_COUNTERS.PeakWorkingSetSize as dword       // The peak working set size, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.WorkingSetSize as dword           // The current working set size, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.QuotaPeakPagedPoolUsage as dword      // The peak paged pool usage, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.QuotaPagedPoolUsage as dword      // The current paged pool usage, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.QuotaPeakNonPagedPoolUsage as dword   // The peak nonpaged pool usage, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.QuotaNonPagedPoolUsage as dword       // The current nonpaged pool usage, in bytes.\r
+    field PROCESS_MEMORY_COUNTERS.PagefileUsage as dword            // The current space allocated for the pagefile, in bytes. Those pages may or may not be in memory.\r
+    field PROCESS_MEMORY_COUNTERS.PeakPagefileUsage as dword        // The peak space allocated for the pagefile, in bytes.\r
+end_type\r
+\r
+// Used by hashing algorithms based on advapi32\r
+type _HCRYPTHASH\r
+    field HCRYPTHASH.value as dword\r
+end_type\r
+\r
+// Used by encryption algorithms based on advapi32\r
+type _HCRYPTKEY\r
+    field HCRYPTKEY.value as dword\r
+end_type\r
+\r
+// Used by encryption algorithms to import / export keys\r
+type _PLAINTEXTKEYBLOB \r
+    field PLAINTEXTKEYBLOB.BLOBHEADER AS char 8 //64 bit\r
+    field PLAINTEXTKEYBLOB.dwKeySize AS dword\r
+    field PLAINTEXTKEYBLOB.rgbKeyData AS char 512\r
+end_type\r
+\r
+// Used by encryption algorithms to import / export keys\r
+type _BLOBHEADER\r
+    field BLOBHEADER.bType AS byte\r
+    field BLOBHEADER.bVersion AS byte\r
+    field BLOBHEADER.Reserved AS word\r
+    field BLOBHEADER.ALG_ID AS byte //UInt\r
+end_type\r
+\r
+// Used for numeric (int,dword,ptr etc) address referencing\r
+type _DW_TYPE\r
+    field DW_TYPE.value as dword\r
+end_type\r
+\r
+// Used by GetVersionEx\r
+type _OSVERSIONINFO\r
+  field OSVERSIONINFO.dwOSVersionInfoSize as dword\r
+  field OSVERSIONINFO.dwMajorVersion as dword\r
+  field OSVERSIONINFO.dwMinorVersion as dword\r
+  field OSVERSIONINFO.dwBuildNumber as dword\r
+  field OSVERSIONINFO.dwPlatformId as dword\r
+  field OSVERSIONINFO.szCSDVersion as char 128\r
+end_type\r
+\r
+// TimeZoneInfo\r
+type _TIME_ZONE_INFORMATION\r
+    field TIME_ZONE_INFORMATION.Bias as dword // long\r
+    field TIME_ZONE_INFORMATION.StandardName as char 64 // wchar array\r
+    field TIME_ZONE_INFORMATION.StandardDate as char 16 // SYSTEMTIME (structure but not actually SYSTEMTIME)\r
+    field TIME_ZONE_INFORMATION.StandardBias as dword // long\r
+    field TIME_ZONE_INFORMATION.DaylightName as char 64 // wchar array (structure but not actually SYSTEMTIME)\r
+    field TIME_ZONE_INFORMATION.DaylightDate as char 16 // SYSTEMTIME\r
+    field TIME_ZONE_INFORMATION.DaylightBias as dword // long\r
+end_type\r
+\r
+//-------------------------------------------------------------------------\r
+// Global arrays used to store results from legacy functions\r
+//-------------------------------------------------------------------------            \r
+\r
+// Global arrays for temporary use by win32 functions\r
+object Win32API_result1 is an array             \r
+end_object\r
+object Win32API_result2 is an array\r
+end_object\r
+object Win32API_result3 is an array\r
+end_object\r
+object Win32API_result4 is an array\r
+end_object\r
+object Win32API_result5 is an array\r
+end_object\r
+\r
+// Used for buffering text files via win32\r
+object Win32API_buffer is an array\r
+end_object\r
+\r
+// Used by list_directory for sorting\r
+object Win32API_sort is an array\r
+end_object\r
+object Win32API_sort1 is an array\r
+end_object\r
+object Win32API_sort2 is an array\r
+end_object\r
+object Win32API_sort3 is an array\r
+end_object\r
+object Win32API_sort4 is an array\r
+end_object\r
+object Win32API_sort5 is an array\r
+end_object\r
+object Win32API_sort6 is an array\r
+end_object\r
+\r
+//-------------------------------------------------------------------------\r
+// Global variables\r
+//-------------------------------------------------------------------------\r
+integer g_sConsoleTitleIsSet\r
+move "" to g_sConsoleTitleIsSet\r
diff --git a/src/df32/win32.inc b/src/df32/win32.inc
new file mode 100644 (file)
index 0000000..5a91c13
--- /dev/null
@@ -0,0 +1,1888 @@
+//-------------------------------------------------------------------------\r
+// win32.inc\r
+//      This file contains DataFlex functions to provide wrappers around "Win32"\r
+//      API calls.  See win32.h for external function definitions.\r
+//\r
+// This file is to be included when using Win32 capabilities in df32func.mk\r
+//\r
+// Copyright (c) 2006-2009, glyn@8kb.co.uk\r
+// \r
+// df32func/win32.inc\r
+//-------------------------------------------------------------------------\r
+\r
+#IFDEF __win32_h__\r
+#ELSE\r
+    #INCLUDE win32.h\r
+#ENDIF\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Takes both the high-order doubleword and low-order doubleword representing the date&time 2X32bit numbers\r
+// and returns as a string\r
+function convert_date_format global dword dwLowDateTime dword dwHighDateTime returns string\r
+    local string sftTime sSystemTime sFormattedTime sFormattedDate sLocalFileTime\r
+    local pointer lpsftTime lpsSystemTime lpsFormattedTime lpsFormattedDate lpsLocalFileTime\r
+    local integer iSuccess iLenCcTime iDataLength iLenCcDate\r
+\r
+    zerotype _FILETIME to sftTime\r
+    put dwLowDateTime to sftTime at FILETIME.dwLowDateTime\r
+    put dwHighDateTime to sftTime at FILETIME.dwHighDateTime\r
+    getaddress of sftTime to lpsftTime\r
+\r
+    zeroType _FILETIME to sLocalFileTime\r
+    getaddress of sLocalFileTime to lpsLocalFileTime\r
+\r
+    move (FileTimeToLocalFileTime(lpsftTime,lpsLocalFileTime)) to iSuccess\r
+    if (iSuccess <> 0) begin\r
+        zerotype _SYSTEMTIME to sSystemTime\r
+        getaddress of sSystemTime to lpsSystemTime\r
+\r
+        move (FileTimeToSystemTime(lpsLocalFileTime,lpsSystemTime)) to iSuccess\r
+        if (iSuccess <> 0) begin\r
+            zerostring 255 to sFormattedTime\r
+            getaddress of sFormattedTime to lpsFormattedTime\r
+            move (length(sFormattedTime)) to iLenCcTime\r
+            move (GetTimeFormat("LOCALE_USER_DEFAULT", 0, lpsSystemTime, 0, lpsFormattedTime, iLenCcTime)) to iDataLength\r
+            \r
+            zerostring 255 To sFormattedDate\r
+            getaddress of sFormattedDate To lpsFormattedDate\r
+            move (length(sFormattedDate)) to iLenCcDate\r
+            move (GetDateFormat("LOCALE_USER_DEFAULT", 0, lpsSystemTime, 0, lpsFormattedDate, iLenCcDate)) to iDataLength\r
+            function_return (cstring (sFormattedDate) * cstring (sFormattedTime)) // return with terminating null char removed\r
+        end\r
+    end\r
+end_function\r
+\r
+// List directory takes a directory path and returns a file count-1\r
+// file listing information including size is put into 5 global arrays\r
+//\r
+// Returns an integer file_count-1, where count represents the number of files found in the directory.\r
+// I.e. If no files are found it will return -1, if one file is found it will return 0\r
+// If files are found, attributes of the files can be found in the following global arrays:\r
+//     \r
+//     Win32API_result1 - File Name\r
+//     Win32API_result2 - File Size\r
+//     Win32API_result3 - Modified Date\r
+//     Win32API_result4 - Access Date\r
+//     Win32API_result5 - Creation Date\r
+// \r
+function list_directory global string argv returns string\r
+    local string sPathName sWin32FindData sLine sLast sComment sFileName sModifiedDate sAccessDate sCreationDate k sLastFile\r
+    local integer l_01iResult iFileSize iFileCount\r
+    local pointer pT5 pT6\r
+    local handle hFile\r
+    local dword dwFileSizeHigh dwFileSizeLow dwHighDateTime dwLowDateTime\r
+\r
+    send delete_data to Win32API_result1\r
+    send delete_data to Win32API_result2\r
+    send delete_data to Win32API_result3\r
+    send delete_data to Win32API_result4\r
+    send delete_data to Win32API_result5\r
+\r
+    zerotype _WIN32_FIND_DATA to sWin32FindData\r
+    getaddress of sWin32FindData to pT5\r
+    move argv to sPathName\r
+    getaddress of sPathName to pT6\r
+    move (FindFirstFile(pT6, pT5)) to hFile\r
+    // if (hFile = -1) showln "Invalid file handle!"\r
+\r
+    move -1 to iFileCount\r
+    repeat \r
+        // FileName\r
+        getbuff_String from sWin32FindData at WIN32_FIND_DATA.cFileName to sFileName\r
+        if ((sFileName <> ".") and (sFileName <> "..") and (sFileName <> "")) begin\r
+            increment iFileCount\r
+\r
+            // FileSize\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeHigh to dwFileSizeHigh\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.nFileSizeLow to dwFileSizeLow\r
+            moveint ((dwFileSizeHigh*MaxDword)+dwFileSizeLow) to iFileSize\r
+\r
+            // File Modified Time\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteLowDateTime to dwLowDateTime\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastWriteHighDateTime to dwHighDateTime\r
+            move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sModifiedDate\r
+   \r
+            // File Accessed Time\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessLowDateTime to dwLowDateTime\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftLastAccessHighDateTime to dwHighDateTime\r
+            move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sAccessDate\r
+   \r
+            // File Creation Time\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationLowDateTime to dwLowDateTime\r
+            getbuff from sWin32FindData at WIN32_FIND_DATA.ftCreationHighDateTime to dwHighDateTime\r
+            move (convert_date_format(dwLowDateTime, dwHighDateTime)) to sCreationDate\r
+\r
+            set array_value of (Win32API_result1(current_object)) item iFileCount to sFileName\r
+            set array_value of (Win32API_result2(current_object)) item iFileCount to iFileSize\r
+            set array_value of (Win32API_result3(current_object)) item iFileCount to sModifiedDate\r
+            set array_value of (Win32API_result4(current_object)) item iFileCount to sAccessDate\r
+            set array_value of (Win32API_result5(current_object)) item iFileCount to sCreationDate\r
+        end\r
+        zerotype _WIN32_FIND_DATA to sWin32FindData\r
+        move (FindNextFile(hFile, pT5)) to l_01iResult\r
+    until (l_01iResult = 0)\r
+    move (FindClose(hFile)) to l_01iResult\r
+\r
+    function_return iFileCount\r
+end_function\r
+\r
+// Sort a directory listing\r
+// argv = array to sort by 1-6, argv2 = array size\r
+// Returns the the data array size\r
+function sort_results global integer argv integer argv2 returns integer\r
+    local integer doneSort l_i l_j l_h l_tmpInt\r
+    local number l_tmpNum\r
+    local string l_tmpStr l_tmpStr2\r
+    local date l_tmpDate\r
+    \r
+    send delete_data to Win32API_sort\r
+    send delete_data to Win32API_sort1\r
+    send delete_data to Win32API_sort2\r
+    send delete_data to Win32API_sort3\r
+    send delete_data to Win32API_sort4\r
+    send delete_data to Win32API_sort5\r
+    send delete_data to Win32API_sort6\r
+\r
+    move 0 to doneSort\r
+    if ((argv < 1) or (argv > 5)) goto sorted\r
+\r
+    for l_i from 0 to argv2\r
+        if (argv = 1) get string_value of (Win32API_result1(current_object)) item l_i to l_tmpStr\r
+        if (argv = 2) get integer_value of (Win32API_result2(current_object)) item l_i to l_tmpInt\r
+        if (argv = 3) get string_value of (Win32API_result3(current_object)) item l_i to l_tmpStr\r
+        if (argv = 4) get string_value of (Win32API_result4(current_object)) item l_i to l_tmpStr\r
+        if (argv = 5) get string_value of (Win32API_result5(current_object)) item l_i to l_tmpStr\r
+\r
+        if (argv = 1) begin\r
+            if ((trim(l_tmpStr)) = "") move "NULL" to l_tmpStr\r
+            set array_value of (Win32API_sort(current_object)) item l_i to (string(lowercase(l_tmpStr)))\r
+        end\r
+        if (argv = 2) set array_value of (Win32API_sort(current_object)) item l_i to l_tmpInt\r
+        if (argv > 2) begin\r
+            calc ((((((integer(mid(l_tmpStr,2,12)))*60)+(integer(mid(l_tmpStr,2,15))))+(((date(mid(l_tmpStr,10,1)))-693975)*1440))*60)+(integer(mid(l_tmpStr,2,18)))) to l_tmpNum\r
+            set array_value of (Win32API_sort(current_object)) item l_i to l_tmpNum\r
+            set array_value of (Win32API_sort6(current_object)) item l_i to l_tmpNum\r
+        end\r
+    loop\r
+\r
+    send sort_items to Win32API_sort ascending\r
+\r
+    for l_i from 0 to argv2\r
+        get string_value of (Win32API_sort(current_object)) item l_i to l_tmpStr\r
+        if ((trim(uppercase(l_tmpStr))) <> "NULL") begin\r
+            for l_j from 0 to argv2\r
+                if (argv = 1) get string_value of (Win32API_result1(current_object)) item l_j to l_tmpStr2\r
+                if (argv = 2) get string_value of (Win32API_result2(current_object)) item l_j to l_tmpStr2\r
+                if (argv > 2) get string_value of (Win32API_sort6(current_object)) item l_j to l_tmpStr2\r
+\r
+                if (((trim(l_tmpStr2)) <> "NULL") and ((trim(l_tmpStr2)) <> "")) begin\r
+                    if ((trim(lowercase(l_tmpStr))) = (trim(lowercase(l_tmpStr2)))) begin\r
+                        get string_value of (Win32API_result1(current_object)) item l_j to l_tmpStr\r
+                        set array_value of (Win32API_sort1(current_object)) item l_i to l_tmpStr\r
+                        get integer_value of (Win32API_result2(current_object)) item l_j to l_tmpInt\r
+                        set array_value of (Win32API_sort2(current_object)) item l_i to l_tmpInt\r
+                        get string_value of (Win32API_result3(current_object)) item l_j to l_tmpStr\r
+                        set array_value of (Win32API_sort3(current_object)) item l_i to l_tmpStr\r
+                        get string_value of (Win32API_result4(current_object)) item l_j to l_tmpStr\r
+                        set array_value of (Win32API_sort4(current_object)) item l_i to l_tmpStr\r
+                        get string_value of (Win32API_result5(current_object)) item l_j to l_tmpStr\r
+                        set array_value of (Win32API_sort5(current_object)) item l_i to l_tmpStr\r
+\r
+                        if (argv = 1) set array_value of (Win32API_result1(current_object)) item l_j to "NULL"\r
+                        if (argv = 2) set array_value of (Win32API_result2(current_object)) item l_j to "NULL"\r
+                        if (argv > 2) set array_value of (Win32API_sort6(current_object)) item l_j to "NULL"\r
+\r
+                        move argv2 to l_j\r
+                    end\r
+                end\r
+            loop\r
+        end\r
+    loop\r
+    for l_i from 0 to argv2\r
+        get string_value of (Win32API_sort1(current_object)) item l_i to l_tmpStr\r
+        set array_value of (Win32API_result1(current_object)) item l_i to l_tmpStr\r
+        get string_value of (Win32API_sort2(current_object)) item l_i to l_tmpInt\r
+        set array_value of (Win32API_result2(current_object)) item l_i to l_tmpInt\r
+        get string_value of (Win32API_sort3(current_object)) item l_i to l_tmpStr\r
+        set array_value of (Win32API_result3(current_object)) item l_i to l_tmpStr\r
+        get string_value of (Win32API_sort4(current_object)) item l_i to l_tmpStr\r
+        set array_value of (Win32API_result4(current_object)) item l_i to l_tmpStr\r
+        get string_value of (Win32API_sort5(current_object)) item l_i to l_tmpStr\r
+        set array_value of (Win32API_result5(current_object)) item l_i to l_tmpStr\r
+    loop\r
+\r
+    send delete_data to Win32API_sort\r
+    send delete_data to Win32API_sort1\r
+    send delete_data to Win32API_sort2\r
+    send delete_data to Win32API_sort3\r
+    send delete_data to Win32API_sort4\r
+    send delete_data to Win32API_sort5\r
+\r
+    sorted:\r
+    function_return doneSort\r
+end_function\r
+\r
+// This function allows basic file operations delete, move, copy, rename\r
+// Useful where DataFlex internal functionssuch as erasefile or copyfile are flakey.\r
+//    \r
+//     fileOpp(<operation type>,<source file>,<dest file>)\r
+//     <operation name> can be any of "COPY", "DELETE", "MOVE" or "RENAME"\r
+//\r
+// Example usage:\r
+//\r
+//     fileOpp("delete","C:\FileTo.delete","")\r
+//     fileOpp("move","C:\Source.file","C:\Destination.file")\r
+//\r
+function fileopp global string argv string argv2 string argv3 returns integer\r
+    local string sFileOp\r
+    local pointer lpFileOp lpArgv2 lpArgv3\r
+    local integer l_iResult\r
+\r
+    move 0 to l_iResult\r
+    move (trim(uppercase(argv))) to argv\r
+    move (trim(argv2)) to argv2\r
+    move (trim(argv3)) to argv3\r
+\r
+    if (((argv = "COPY") or (argv = "PRINT") or (argv = "DELETE") or (argv = "MOVE") or (argv = "RENAME")) and (argv2 <> "")) begin\r
+        zerotype _SHFILEOPSTRUCT to sFileOp\r
+        getaddress of sFileOp to lpFileOp\r
+\r
+        case begin\r
+            case (argv = "COPY") put FO_COPY to sFileOp at SHFILEOPSTRUCT.wFunc\r
+            case break\r
+            case (argv = "PRINT") put FO_COPY to sFileOp at SHFILEOPSTRUCT.wFunc\r
+            case break\r
+            case (argv = "DELETE") put FO_DELETE to sFileOp at SHFILEOPSTRUCT.wFunc\r
+            case break\r
+            case (argv = "MOVE") put FO_MOVE to sFileOp at SHFILEOPSTRUCT.wFunc\r
+            case break\r
+            case (argv = "RENAME") put FO_RENAME to sFileOp at SHFILEOPSTRUCT.wFunc\r
+            case break\r
+        case end\r
+\r
+        move (argv2+character(0)+character(0)) to argv2\r
+        move (argv3+character(0)+character(0)) to argv3\r
+        getAddress of argv2 to lpArgv2\r
+        put lpArgv2 to sFileOp at SHFILEOPSTRUCT.pFrom\r
+        \r
+        if (argv <> "DELETE") begin\r
+            getAddress Of argv3 to lpArgv3\r
+            put lpArgv3 to sFileOp at SHFILEOPSTRUCT.pTo\r
+        end  \r
+\r
+        case begin\r
+            case (argv = "PRINT") put (FOF_NOCONFIRMATION+FOF_NOCONFIRMMKDIR+FOF_SILENT+FOF_NOERRORUI+FOF_NOCOPYSECURITYATTRIBS) to sFileOp at SHFILEOPSTRUCT.fFlags\r
+            case break\r
+            case else put (FOF_NOCONFIRMATION+FOF_NOCONFIRMMKDIR+FOF_SILENT+FOF_NOERRORUI) to sFileOp at SHFILEOPSTRUCT.fFlags\r
+            case break\r
+        case end\r
+            \r
+        // put ? to sFileOp at SHFILEOPSTRUCT.hWnd\r
+        // put ? to sFileOp at SHFILEOPSTRUCT.fAnyOperationsAborted\r
+        // put ? to sFileOp at SHFILEOPSTRUCT.hNameMappings\r
+        // put ? to sFileOp at SHFILEOPSTRUCT.lpszProgressTitle\r
+\r
+        move (SHFileOperation(lpFileOp)) to l_iResult\r
+    end\r
+\r
+    function_return l_iResult\r
+end_function\r
+\r
+// Get temp dir on local machine from windows registry\r
+function get_local_temp global integer argv returns string\r
+    local string lpBuffer\r
+    local integer l_01iResult\r
+    local pointer tmpPtr\r
+    \r
+    move (pad(lpBuffer,255)) to lpBuffer // this is a hack to allocate a specific size to a local string\r
+    getaddress of lpBuffer to tmpPtr\r
+    move (GetTempPath(255,tmpPtr)) to l_01iResult\r
+\r
+    function_return lpbuffer\r
+end_function\r
+\r
+// Get system dir on local machine from windows registry\r
+function get_local_system global integer argv returns string\r
+    local string sBuffer\r
+    local pointer lpBuffer l_iResult uSize\r
+\r
+    move 255 to uSize\r
+    move (repeat(character(0),(uSize+1))) to sBuffer    \r
+    getAddress of sBuffer to lpBuffer\r
+    move (GetSystemDirectory(lpBuffer,uSize)) to l_iResult      \r
+    \r
+    function_return (left(sBuffer,l_iResult))\r
+end_function\r
+\r
+// Function to open close cd tray dll - 0 to open 1 to close\r
+function cd_tray global integer argv returns integer\r
+    local integer l_iResult\r
+    local string l_sReturn l_sCmd   \r
+    local pointer l_pCmd l_pReturn\r
+    \r
+    zerostring 127 to l_sCmd    \r
+    getaddress of l_sCmd to l_pCmd\r
+    getaddress of l_sReturn to l_pReturn\r
+\r
+    if (argv = 0) move "set CDAudio door open" to l_sCmd\r
+    if (argv = 1) move "set CDAudio door closed" to l_sCmd\r
+    move (mciSendString(l_pCmd,l_pReturn,127,0)) to l_iResult\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+// This function will force dataflex to exit with the error code in iReturnCode\r
+function exit_process global integer iReturnCode returns integer\r
+  local integer iVoid\r
+  \r
+  move (ExitProcessEx(iReturnCode)) To iVoid\r
+  \r
+  function_return iVoid\r
+end_function\r
+\r
+// Grab the process ID of dfruncon\r
+function get_process_id global integer argv returns integer\r
+    local integer iRVal\r
+    \r
+    move (GetPID()) TO iRVal\r
+    \r
+    function_return (Low(iRVal))\r
+end_function\r
+\r
+// Grab the computername\r
+function get_computer global integer argv returns string\r
+    local string  strName lsSize\r
+    local pointer lpNameAddr lpSize\r
+    local integer l_01iResult\r
+\r
+    move (repeat(character(0),255)) to strName\r
+    getAddress of strName to lpNameAddr\r
+    move (repeat(character(0),_SIZEGETCOMPUTERNAME_SIZE)) to lsSize\r
+    put 16 to lsSize at SIZEGETCOMPUTERNAME.dwSize\r
+    getAddress of lsSize to lpSize\r
+    move (GetComputername(lpNameAddr, lpSize )) to l_01iResult\r
+    \r
+    if (l_01iResult) function_return (cstring(strName)) // return with terminating null char removed\r
+    else function_return "Unknown"\r
+end_function\r
+    \r
+// Grab the windows username\r
+function get_user_name global integer argv returns string\r
+    local string strName\r
+    local pointer lpNameAddr\r
+    local integer l_01iResult\r
+\r
+    move (repeat(character(0),255)) to strName\r
+    getAddress of strName to lpNameAddr\r
+    move (WNetGetUser(0, lpNameAddr, DWORDtoBytes(255))) to l_01iResult\r
+    if (l_01iResult = 0) function_return (uppercase(cstring(strName))) // return with terminating null char removed\r
+    else function_return "Unknown"\r
+end_function\r
+\r
+// Use a standard windows folder browser, takes the title of the browser, returns the file path\r
+function folder_browse global string argv returns String\r
+    local string sFolder sBrowseInfo sTitle\r
+    local pointer lpItemIdList lpsFolder lpsBrowseInfo lpsTitle\r
+    integer iFolderSelected l_iRetval\r
+\r
+    zeroType _BROWSEINFO to sBrowseInfo\r
+\r
+    if (argv<>"") begin\r
+        move argv to sTitle\r
+        getAddress of sTitle to lpsTitle\r
+        put lpsTitle to sBrowseInfo at BROWSEINFO.lpszTitle\r
+    end\r
+\r
+    put BIF_RETURNONLYFSDIRS+BIF_EDITBOX+BIF_BROWSEINCLUDEFILES to sBrowseInfo At BROWSEINFO.ulFlags\r
+    // put (window_handle(focus(desktop))) to sBrowseInfo At BROWSEINFO.hWndOwner ??\r
+    move (repeat(character(0),260)) to sFolder // set the size of sFolder to 128 by nulling in 8 chars\r
+    \r
+    getAddress Of sBrowseInfo to lpsBrowseInfo\r
+    getAddress Of sFolder to lpsFolder\r
+\r
+    move (SHBrowseForFolder(lpsBrowseInfo)) to lpItemIdList // select folder\r
+    move (SHGetPathFromIDList(lpItemIdList, lpsFolder)) to iFolderSelected // get folder name\r
+    move (CoTaskMemFree(lpItemIdList)) to l_iRetval // release memory used by ItemIdList\r
+\r
+    if (iFolderSelected = 0)  move "" to sFolder\r
+    \r
+    function_return (cString(sFolder)) // return with terminating null char removed\r
+end_function\r
+\r
+// Function to convert a long filename into a windows short filename\r
+function get_short_path global string argv returns string\r
+    local string sShortPath sLongPath\r
+    local pointer lpszShortPath lpszLongPath\r
+    local integer cchBuffer l_iResult\r
+    \r
+    move (trim(argv)) to sLongPath\r
+    move 255 to cchBuffer\r
+    move (repeat(character(0),(cchBuffer+1))) to sShortPath\r
+    getaddress of sLongPath to lpszLongPath\r
+    getaddress of sShortPath to lpszShortPath\r
+    move (GetShortPathName(lpszLongPath,lpszShortPath,cchBuffer)) to l_iResult\r
+    \r
+    function_return (left(sShortPath,l_iResult))\r
+end_function\r
+\r
+// Set of function to disable close widgets of shell\r
+function disable_close global integer argv returns integer\r
+    local number Ret\r
+    local handle hWnd hMenu\r
+\r
+    if (g_sConsoleTitleIsSet <> "DataFlex") begin\r
+        // change the window title so we can find the window\r
+        move (SetConsoleTitle("DataFlex")) to strmark \r
+        move "DataFlex" to g_sConsoleTitleIsSet\r
+        //  Give SetConsoleTitle a chance to take effect\r
+        sleep 1\r
+    end\r
+    \r
+    // find the window\r
+    move (FindWindow(0, "DataFlex")) to hWnd\r
+    // grab the menu\r
+    move (GetSystemMenu(hWnd, 0)) to hMenu\r
+    // disable the X\r
+    if (argv = 0) move (EnableMenuItem(hMenu, SC_CLOSE, (MF_BYCOMMAND ior MF_GRAYED))) to ret\r
+    // enable the X    \r
+    if (argv = 1) move (EnableMenuItem(hMenu, SC_CLOSE, (MF_BYCOMMAND ior MF_ENABLED))) to ret\r
+    \r
+    function_return 0\r
+end_function\r
+\r
+// This function will run any external application directly from dataflex\r
+// argv = application to run (command name/path) argv2 = any parameters to pass to the program argv3 = directory to run from\r
+function shell_exec global string argv string argv2 string argv3 returns integer\r
+    local handle windowHandle\r
+    local pointer lpOperation lpFile lpParameters lpDirectory\r
+    local integer nShowCmd l_iResult\r
+    local string sOperation sFile sParameters sDirectory\r
+\r
+    if ((trim(argv)) <> "") begin\r
+        move 0 to windowHandle\r
+        move "open" to sOperation\r
+        move argv to sFile\r
+        if ((trim(argv2)) <> "") move argv2 to sParameters\r
+        else move "" to sParameters \r
+        if ((trim(argv3)) <> "") move argv3 to sDirectory\r
+        else move "" to sDirectory\r
+        move "" to sDirectory\r
+\r
+        getAddress of sOperation to lpOperation\r
+        getAddress of sFile to lpFile\r
+        getAddress of sParameters to lpParameters\r
+        getAddress of sDirectory to lpDirectory\r
+\r
+        move (ShellExecute(windowHandle,lpOperation,lpFile,lpParameters,lpDirectory,SW_SHOWMAXIMIZED)) to l_iResult\r
+    end\r
+end_function\r
+\r
+// This function will run the console application stated in argv1\r
+// argv2 = set to 1 to run the process in a new window\r
+// argv3 = set to 1 to leave the new process running and continue without killing it\r
+// argv4  = The time to live before killing the process - set to zero to wait until finished\r
+// Note - Setting argv3 to 1 will result in build up of open handles for finished processes \r
+//        if term_proc is not used to terminate the process.\r
+// It is possible to have multiple processes running in one window by\r
+// setting argv2 = 0 and argv3 = 1, but handling how they behave on the screen \r
+// requires some careful fiddling.\r
+function create_proc global string argv integer argv2 integer argv3 integer argv4 returns string\r
+    local pointer lpProcessInformation lpStartupInformation\r
+    local integer l_iResult\r
+    local pointer lpApplicationName lpCommandLine lpProcessAttributes lpThreadAttributes lpEnvironment lpCurrentDirectory\r
+    local integer bInheritHandles iProcessAttributes iThreadAttributes iEnvironment \r
+    local dword dwCreationFlags dwMilliseconds\r
+    local string sProcessInformation sStartupInformation sApplicationName sCommandLine sCurrentDirectory l_sExit l_sTmp\r
+    local handle hProcess hThread\r
+    \r
+    zeroType _PROCESS_INFORMATION to sProcessInformation\r
+    zeroType _STARTUPINFO to sStartupInformation\r
+\r
+    move STRINGNULL to l_sExit\r
+    move STRINGNULL to sApplicationName\r
+    move argv to sCommandLine\r
+    move HEXNULL to iProcessAttributes\r
+    move HEXNULL to iThreadAttributes\r
+    move HEXTRUE to bInheritHandles\r
+    move HEXNULL to iEnvironment\r
+    move STRINGNULL to sCurrentDirectory\r
+    if (argv2 = 0) move NORMAL_PRIORITY_CLASS to dwCreationFlags\r
+    if (argv2 = 1) move (CREATE_NEW_CONSOLE+NORMAL_PRIORITY_CLASS) to dwCreationFlags\r
+    \r
+    getaddress of sApplicationName to lpApplicationName\r
+    getaddress of sCommandLine to lpCommandLine\r
+    getaddress of iProcessAttributes to lpProcessAttributes\r
+    getaddress of iThreadAttributes to lpThreadAttributes\r
+    getaddress of iEnvironment to lpEnvironment\r
+    getaddress of sCurrentDirectory to lpCurrentDirectory\r
+    getaddress of sProcessInformation to lpProcessInformation\r
+    getaddress of sStartupInformation to lpStartupInformation\r
+    \r
+    put (length(sStartupInformation)) to sStartupInformation at STARTUPINFO.cb\r
+    \r
+    move (CreateProcess(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,dwCreationFlags,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInformation,lpProcessInformation)) to l_iResult\r
+    \r
+    getbuff from sProcessInformation at PROCESS_INFORMATION.hProcess to hProcess\r
+    getbuff from sProcessInformation at PROCESS_INFORMATION.hThread to hThread\r
+\r
+    if (argv3 <> 1) begin\r
+        if (argv4 = 0) move INFINITE to dwMilliseconds\r
+        if (argv4 <> 0) move argv4 to dwMilliseconds\r
+        move (WaitForSingleObject(hProcess,dwMilliseconds)) to l_iResult\r
+        move (TerminateProcess(hProcess,HEXNULL)) to l_iResult\r
+        move (CloseHandle(hThread)) to l_iResult\r
+        move (CloseHandle(hProcess)) to l_iResult\r
+    end\r
+    if (argv3 = 1) begin                \r
+        move hProcess to l_sExit\r
+        append l_sExit "|" hThread\r
+    end\r
+    \r
+    function_return l_sExit\r
+end_function\r
+\r
+// This will terminate a process started in create_proc with argv3 set to 1\r
+// move the string returned by create_proc to argv\r
+// set argv2 to 0 if you want to wait for the process to finish before terminating\r
+// set argv2 to 1 if you want to terminate the process without waiting for it to finish\r
+function term_proc global string argv integer argv2 returns integer\r
+    local integer l_iSuccess\r
+    local integer dwMilliseconds l_iResult\r
+    local handle hProcess hThread\r
+    \r
+    move 0 to l_iSuccess\r
+    move (trim(argv)) to argv\r
+    if ((argv contains "|") and ((length(argv)) >= 3)) begin    \r
+        move (left(argv,(pos("|",argv)-1))) to hProcess\r
+        move (mid(argv,(length(argv)-pos("|",argv)),(pos("|",argv)+1))) to hThread\r
+        move INFINITE to dwMilliseconds\r
+        if (argv2 = 0) move (WaitForSingleObject(hProcess,dwMilliseconds)) to l_iResult\r
+        move (TerminateProcess(hProcess,HEXNULL)) to l_iResult\r
+        move (CloseHandle(hThread)) to l_iResult\r
+        move (CloseHandle(hProcess)) to l_iResult\r
+    end\r
+    \r
+    function_return l_iSuccess\r
+end_function\r
+\r
+// Check if a file is locked by a windows process\r
+// Returns 1 if the file is locked.\r
+function is_locked global string argv returns integer\r
+    local integer l_iResult l_iDllErr l_iThrow\r
+    local handle l_hFile    \r
+    move 0 to l_iResult\r
+    move -1 to l_hFile\r
+    move (trim(argv)) to argv   \r
+    if (argv <> "") begin\r
+        move (lOpen(argv,(OF_READ+OF_SHARE_EXCLUSIVE))) to l_hFile\r
+        move (GetLastError()) to l_iDllErr\r
+        if ((l_hFile = -1) and (l_iDllErr = 32)) move 1 to l_iResult\r
+        if (l_hFile <> -1) begin\r
+            move (lClose(l_hFile)) to l_iThrow\r
+        end\r
+    end\r
+    function_return l_iResult\r
+end_function\r
+\r
+// Check if a file exists. Returns 1 if the file exists.\r
+function does_exist global string argv returns integer\r
+    local integer l_iResult l_iDllErr l_iThrow\r
+    local handle l_hFile    \r
+    move 0 to l_iResult\r
+    move -1 to l_hFile\r
+    move (trim(argv)) to argv   \r
+    if (argv <> "") begin\r
+        move 1 to l_iResult\r
+        move (lOpen(argv,(OF_READ+OF_SHARE_DENY_NONE))) to l_hFile\r
+        move (GetLastError()) to l_iDllErr\r
+        if ((l_hFile = -1) and (l_iDllErr = 2)) move 0 to l_iResult\r
+        if (l_hFile <> -1) begin\r
+            move (lClose(l_hFile)) to l_iThrow\r
+        end\r
+    end\r
+    function_return l_iResult\r
+end_function\r
+\r
+// Read a text file line by line into the buffer array "Win32API_buffer"\r
+// Returns an integer i-1 where i is the count of array elements/lines.\r
+//\r
+// Ref: http:// msdn2.microsoft.com/en-us/library/aa365467.aspx\r
+function buffer_text_file global string argv string argv2 returns integer\r
+    local string l_sBuf l_sBufL l_structBytesRead l_sLine // String l_structBytesRead used with struct to overcome problem of df not being able to getaddress of integers\r
+    local handle l_hFileHandle l_hFile\r
+    local pointer l_pFileName l_pBuf l_pBytesRead\r
+    local integer l_iFileSize l_iThrow l_iBytesRead l_iBytesToRead l_i l_iDllErr l_iLines\r
+    \r
+    send delete_data to Win32API_buffer\r
+    move -1 to l_iLines\r
+    \r
+    move (trim(argv)) to argv\r
+    move (trim(argv2)) to argv2\r
+    move -1 to l_hFileHandle\r
+    move 0 to l_iBytesRead\r
+    move 1 to l_iBytesToRead\r
+    move "" to l_sLine\r
+    \r
+    if (argv <> "") begin\r
+        getaddress of argv to l_pFileName\r
+        move (CreateFile(l_pFileName,GENERIC_READ,FILE_SHARE_READ,HexNull,OPEN_EXISTING,0,HexNull)) to l_hFile\r
+        move (GetFileSize(l_hFile,0)) to l_iFileSize\r
+        for l_i from 1 to l_iFileSize\r
+            // move (SetFilePointer(l_hFile,l_i,0,FILE_CURRENT)) to l_iThrow\r
+            zerostring 1 to l_sBuf\r
+            getaddress of l_sBuf to l_pBuf\r
+            zerotype _STRUCTBYTESREAD to l_structBytesRead\r
+            getaddress of l_structBytesRead to l_pBytesRead\r
+            move (ReadFile(l_hFile,l_pBuf,l_iBytesToRead,l_pBytesRead,HexNull)) to l_iThrow\r
+            getbuff from l_structBytesRead at STRUCTBYTESREAD.integer0 to l_iBytesRead\r
+            if ((ascii(l_sBuf) = 10) or (ascii(l_sBuf) = 13) or ((argv2 <> "") and (argv2 = l_sBuf))) begin\r
+                if (ascii(l_sBufL) <> 13) begin\r
+                    increment l_iLines\r
+                    set array_value of (Win32API_buffer(current_object)) item l_iLines to l_sLine\r
+                    move "" to l_sLine\r
+                end\r
+                \r
+            end\r
+            if ((ascii(l_sBuf) <> 10) and (ascii(l_sBuf) <> 13) and ((argv2 = "") or (argv2 <> l_sBuf))) append l_sLine l_sBuf\r
+            move l_sBuf to l_sBufL\r
+        end \r
+        move (CloseHandle(l_hFile)) to l_iThrow\r
+    end\r
+    function_return l_iLines\r
+end_function\r
+\r
+// Return file size in bytes from win32\r
+function file_size_bytes global string argv returns integer\r
+    local integer l_iFileSize l_iThrow\r
+    local pointer l_pFileName\r
+    local handle l_hFile\r
+    \r
+    move -1 to l_iFileSize\r
+    \r
+    if (argv <> "") begin\r
+        getaddress of argv to l_pFileName\r
+        move (CreateFile(l_pFileName,GENERIC_READ,FILE_SHARE_READ,HexNull,OPEN_EXISTING,0,HexNull)) to l_hFile\r
+        move (GetFileSize(l_hFile,0)) to l_iFileSize\r
+        move (CloseHandle(l_hFile)) to l_iThrow\r
+    end\r
+    \r
+    function_return l_iFileSize\r
+end_function\r
+\r
+// Attempt to convert a string from unicode to ASCII/cp850 via WideCharToMultiByte\r
+// http:// msdn2.microsoft.com/en-us/library/ms776420.aspx\r
+function to_ascii global string argv returns string\r
+    local string l_sAscii l_sUnicode\r
+    local pointer l_pAscii l_pUnicode\r
+    local integer l_iCharsNeeded l_iThrow\r
+    move (trim(argv)) to l_sUnicode\r
+    \r
+    if (l_sUnicode <> "") begin\r
+        zerostring 100 to l_sAscii\r
+        getAddress of l_sAscii to l_pAscii\r
+        getAddress of l_sUnicode to l_pUnicode\r
+        \r
+        // set the length of cchWideChar to -1 and function assumes null termination and calculates lenght itsself\r
+        move (WideCharToMultiByte(CP_OEMCP,0,l_pUnicode,-1,0,0,0,0)) to l_iCharsNeeded              \r
+        move (WideCharToMultiByte(CP_OEMCP,0,l_pUnicode,-1,l_pAscii,l_iCharsNeeded,0,0)) to l_iThrow\r
+    end\r
+    function_return l_sAscii\r
+end_function\r
+\r
+// Attempt to convert a string from ASCII to unicode via MultiByteToWideChar\r
+function to_unicode global string argv returns string\r
+    local string l_sAscii l_sUnicode\r
+    local pointer l_pAscii l_pUnicode\r
+    local integer l_iCharsNeeded l_iThrow\r
+    move (trim(argv)) to l_sAscii\r
+    \r
+    if (l_sAscii <> "") begin\r
+        zerostring 100 to l_sUnicode\r
+        getAddress of l_sUnicode to l_pUnicode\r
+        getAddress of l_sAscii to l_pAscii\r
+        \r
+        // set the length of cchWideChar to -1 and function assumes null termination and calculates lenght itsself\r
+        move (MultiByteToWideChar(CP_ACP,0,l_pAscii,-1,0,0,0,0)) to l_iCharsNeeded              \r
+        move (MultiByteToWideChar(CP_ACP,0,l_pAscii,-1,l_pUnicode,l_iCharsNeeded,0,0)) to l_iThrow\r
+    end\r
+    function_return l_sUnicode  \r
+end_function\r
+\r
+// Attempt to convert a string from ascii to UTF8 via WideCharToMultiByte\r
+function to_utf8 global string argv returns string\r
+    local string l_sUTF8 l_sUnicode\r
+    local pointer l_pUTF8 l_pUnicode\r
+    local integer l_iCharsNeeded l_iThrow\r
+    move (trim(argv)) to l_sUnicode\r
+    \r
+    if (l_sUnicode <> "") begin\r
+        zerostring 100 to l_sUTF8\r
+        getAddress of l_sUTF8 to l_pUTF8\r
+        getAddress of l_sUnicode to l_pUnicode\r
+        \r
+        // set the length of cchWideChar to -1 and function assumes null termination and calculates lenght itsself\r
+        move (WideCharToMultiByte(CP_UTF8,0,l_pUTF8,-1,0,0,0,0)) to l_iCharsNeeded              \r
+        move (WideCharToMultiByte(CP_UTF8,0,l_pUTF8,-1,l_pUnicode,l_iCharsNeeded,0,0)) to l_iThrow\r
+    end\r
+    \r
+    function_return l_sUTF8\r
+end_function\r
+\r
+// Get running processes on the system\r
+// http:// msdn2.microsoft.com/en-us/library/ms682629.aspx\r
+// in progress - currently churns out list of process id's to screen\r
+function get_procs global integer argv returns integer\r
+    local string l_sProcesses l_sStructBytesBack l_sBuf l_sModules\r
+    local integer l_iThrow l_iBytes l_iBytes2 l_iBytesBack l_iBytesBack2 l_i l_j l_iPid l_iMid\r
+    local pointer l_pProcesses l_pBytesBack l_pBytesBack2 l_pModules\r
+    local handle l_hProcess\r
+    \r
+    move (1024*10) to l_iBytes  \r
+    zerostring l_iBytes to l_sProcesses\r
+    move 0 to l_iBytesBack\r
+    \r
+    getAddress of l_sProcesses to l_pProcesses  \r
+    zerotype _STRUCTBYTESBACK to l_sStructBytesBack\r
+    getaddress of l_sStructBytesBack to l_pBytesBack\r
+    \r
+    move (EnumProcesses(l_pProcesses,l_iBytes,l_pBytesBack)) to l_iThrow\r
+\r
+    getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack\r
+    \r
+    if (mod(l_iBytesBack,4) = 0) begin\r
+        for l_i from 1 to (l_iBytesBack/4)\r
+            move (left(l_sProcesses,4)) to l_sBuf\r
+            move (mid(l_sProcesses,(length(l_sProcesses)-4),5)) to l_sProcesses\r
+            getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iPid     \r
+            move (OpenProcess((PROCESS_VM_READ ior PROCESS_QUERY_INFORMATION),HEXNULL,l_iPid)) to l_hProcess\r
+            \r
+            move 1024 to l_iBytes2\r
+            zerostring l_iBytes2 to l_sModules\r
+            getAddress of l_sModules to l_pModules\r
+            zerotype _STRUCTBYTESBACK to l_sStructBytesBack\r
+            getaddress of l_sStructBytesBack to l_pBytesBack2\r
+            \r
+            move (EnumProcessModules(l_hProcess,l_pModules,l_iBytes2,l_pBytesBack2)) to l_iThrow\r
+            getbuff from l_sStructBytesBack at STRUCTBYTESBACK.integer0 to l_iBytesBack2\r
+            \r
+            // Err here            \r
+            showln l_i  " PROC=" l_iPid " BYTES=" l_iBytesBack2 " H=" l_hProcess " LERR=" (GetLastError())\r
+            \r
+            // showln l_iBytesBack2 " " l_hProcess\r
+            if (mod(l_iBytesBack2,4) = 0) begin\r
+                for l_j from 1 to (l_iBytesBack2/4)\r
+                    move (left(l_sModules,4)) to l_sBuf\r
+                    move (mid(l_sModules,(length(l_sModules)-4),5)) to l_sModules\r
+                    getbuff from l_sBuf at PROCESSARRAY.arrayItem to l_iMid\r
+\r
+                loop\r
+            end\r
+            move (CloseHandle(l_hProcess)) to l_iThrow\r
+            \r
+        loop\r
+    end\r
+        \r
+    showln l_iThrow\r
+    showln "BYTES " l_iBytesBack\r
+    \r
+    function_return 0\r
+end_function\r
+\r
+// Returns the current system time via the GetSystemTime call\r
+// Takes an integer value; \r
+//     1 - displays individual segments comma separated\r
+//     0 - displays a formatted date time\r
+function time_data global integer argv returns string\r
+    local string sTimeData sResult sFormattedTime sFormattedDate\r
+    local pointer pTimeData pFormattedTime pFormattedDate\r
+    local integer iThrow iYear iMonth iDayOfWeek iDay iHour iMinute iSecond iMilliSeconds iLenCcTime iLenCcDate iDataLength\r
+    \r
+    zeroType _SYSTEMTIME to sTimeData\r
+    getAddress of sTimeData to pTimeData\r
+    move (GetSystemTime(pTimeData)) to iThrow\r
+    \r
+    // just return the structure comma separated\r
+    if (argv = 1) begin\r
+        getBuff from sTimeData at SYSTEMTIME.wYear to iYear\r
+        getBuff from sTimeData at SYSTEMTIME.wMonth to iMonth\r
+        getBuff from sTimeData at SYSTEMTIME.wDayOfWeek to iDayOfWeek\r
+        getBuff from sTimeData at SYSTEMTIME.wDay to iDay\r
+        getBuff from sTimeData at SYSTEMTIME.wHour to iHour\r
+        getBuff from sTimeData at SYSTEMTIME.wMinute to iMinute\r
+        getBuff from sTimeData at SYSTEMTIME.wSecond to iSecond\r
+        getBuff from sTimeData at SYSTEMTIME.wMilliSeconds to iMilliSeconds\r
+        \r
+        move "" to sResult\r
+        append sResult iYear "," iMonth "," iDay "," iHour "," iMinute "," iSecond "," iMilliSeconds\r
+    end \r
+    // give formatted date_time\r
+    if (argv = 0) begin \r
+        zerostring 255 to sFormattedTime\r
+        getaddress of sFormattedTime to pFormattedTime\r
+        move (length(sFormattedTime)) to iLenCcTime\r
+    \r
+        move (GetTimeFormat("LOCALE_USER_DEFAULT", 0, pTimeData, 0, pFormattedTime, iLenCcTime)) to iDataLength\r
+\r
+        zerostring 255 To sFormattedDate\r
+        getaddress of sFormattedDate To pFormattedDate\r
+        move (length(sFormattedDate)) to iLenCcDate\r
+    \r
+        move (GetDateFormat("LOCALE_USER_DEFAULT", 0, pTimeData, 0, pFormattedDate, iLenCcDate)) to iDataLength\r
+        move (cstring(sFormattedDate)) to sResult\r
+        append sResult " " (cstring(sFormattedTime)) // terminating null char removed    \r
+    end\r
+    function_return sResult\r
+end_function\r
+\r
+// Insert zeros into the correct places to make a field x wide (similar to zeropad)\r
+function fill_0 global integer iValue integer iSize returns string\r
+    local string sReturn\r
+\r
+    move iValue to sReturn\r
+    while (length(sReturn) < iSize)\r
+        insert '0' in sReturn at 1\r
+    end\r
+\r
+    function_return sReturn\r
+end_function\r
+\r
+// Checks the runtime date format and if it's not adding on the epoch add it\r
+function check_date_error global string sDate returns date\r
+    local integer iDate iY1k\r
+    local Date    dDate\r
+\r
+    move sDate to iDate\r
+    move 693975 to iY1k\r
+\r
+    if (iDate < iY1k) Calc (iDate + iY1k) to iDate\r
+    move iDate to dDate\r
+\r
+    function_return dDate\r
+end_function\r
+\r
+// Get the mod time of a file\r
+// This is the core of the replacement / leap year fix of GET_FILE_MOD_TIME\r
+// Usage:\r
+// get_time(<file>, <mode>)\r
+//     1 = created time\r
+//     2 = accessed time\r
+//     3 = modified time\r
+// \r
+function get_time global string sFileName integer iMode returns string\r
+    local string  sCreated sLastAccess sLastChanged sSystemTime sLocalTime sDate sTime sDateSep\r
+    Local pointer pCreated pLastAccess pLastChanged pSystemTime pLocalTime pFileName\r
+    Local handle  hCheckFile\r
+    Local integer iResult iVal iDateSep iDateFormat iDate4State\r
+\r
+    move "" to sTime\r
+    move "" to sDate\r
+    \r
+    getaddress of sFileName to pFileName\r
+    move (CreateFile(pFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING , 0, 0)) to hCheckFile\r
+    \r
+    if (hCheckFile <> INVALID_HANDLE_VALUE) begin\r
+        zerotype _FILETIME to sCreated\r
+        zerotype _FILETIME to sLastAccess\r
+        zerotype _FILETIME to sLastChanged\r
+        zerotype _FILETIME to sLocalTime\r
+        getAddress of sCreated to pCreated\r
+        getAddress of sLastAccess to pLastAccess\r
+        getAddress of sLastChanged to pLastChanged\r
+        getAddress of sLocalTime to pLocalTime\r
+\r
+        move (GetFileTime (hCheckFile, pCreated, pLastAccess, pLastChanged)) to iResult \r
+          \r
+        if (iResult) begin\r
+            if (iMode = 1) move (FileTimeToLocalFileTime(pCreated,pLocalTime)) to iResult\r
+            else if (iMode = 2) move (FileTimeToLocalFileTime(pLastAccess,  pLocalTime)) to iResult\r
+            else if (iMode = 3) move (FileTimeToLocalFileTime(pLastChanged, pLocalTime)) to iResult\r
+            \r
+            zerotype _SYSTEMTIME2 to sSystemTime\r
+            getAddress of sSystemTime to pSystemTime\r
+\r
+            move (FileTimeToSystemTime(pLocalTime, pSystemTime)) to iResult\r
+\r
+            get_attribute DF_DATE_SEPARATOR to iDateSep\r
+            move (character(iDateSep))   to sDateSep\r
+            get_attribute DF_DATE_FORMAT to iDateFormat\r
+\r
+            if (iDateFormat = DF_DATE_USA) begin\r
+                getbuff from sSystemTime at SYSTEMTIME2.wMonth to iVal\r
+                append sDate (fill_0(iVal,2))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wDay to iVal\r
+                append sDate sDateSep (fill_0(iVal,2))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wYear to iVal\r
+                append sDate sDateSep (fill_0(iVal,4))\r
+            end\r
+            else if iDateFormat eq DF_DATE_EUROPEAN begin\r
+                getbuff from sSystemTime at SYSTEMTIME2.wDay to iVal\r
+                append sDate (fill_0(iVal,2))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wMonth to iVal\r
+                append sDate sDateSep (fill_0(iVal,2))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wYear to iVal\r
+                append sDate sDateSep (fill_0(iVal,4))\r
+            end\r
+            else if iDateFormat eq DF_DATE_MILITARY begin\r
+                getbuff from sSystemTime at SYSTEMTIME2.wYear to iVal\r
+                append sDate (fill_0(iVal,4))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wMonth to iVal\r
+                append sDate sDateSep (fill_0(iVal,2))\r
+                getbuff from sSystemTime at SYSTEMTIME2.wDay to iVal\r
+                append sDate sDateSep (fill_0(iVal,2))\r
+            end\r
+\r
+            getbuff from sSystemTime at SYSTEMTIME2.wHour to iVal\r
+            append sTime (fill_0(iVal,2))\r
+            getbuff from sSystemTime at SYSTEMTIME2.wMinute to iVal\r
+            append sTime ":" (fill_0(iVal,2))\r
+            getbuff from sSystemTime at SYSTEMTIME2.wSecond to iVal\r
+            append sTime ":" (fill_0(iVal,2))\r
+\r
+            append sDate sTime\r
+        end\r
+        move (CloseHandle (hCheckFile)) to iResult\r
+    end\r
+\r
+    function_return sDate\r
+end_function\r
+\r
+// Create a guid GUID (Microsoft)\r
+function create_guid global returns string        \r
+    local integer l_iThrow\r
+    local pointer l_ptGUID l_ptGUIDString\r
+    local string l_stGUID l_stGUIDString l_sResult\r
+   \r
+    zerotype _GUID to l_stGUID\r
+    getaddress of l_stGUID to l_ptGUID\r
+\r
+    zerostring GUID_STRING_LENGTH to l_stGUIDString\r
+    getaddress of l_stGUIDString to l_ptGUIDString\r
+    \r
+    if (CoCreateGuid(l_ptGUID) = 0) begin\r
+        // If successfully created put it in a string\r
+        move (StringFromGUID2(l_ptGUID, l_ptGUIDString, GUID_STRING_LENGTH)) to l_iThrow\r
+        move (cstring(to_ascii(l_stGUIDString))) to l_sResult\r
+    end\r
+    \r
+    function_return l_sResult\r
+end_function\r
+\r
+// Get textual description of a win32 error returned by GetLastError()\r
+function get_last_error_detail global integer iError returns string\r
+    local integer l_iThrow\r
+    local string l_sBuf \r
+    local pointer l_pBuf\r
+    \r
+    zerostring 200 to l_sBuf\r
+    getaddress of l_sBuf to l_pBuf\r
+    \r
+    move (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, iError, LANG_NEUTRAL, l_pBuf, 200, 0)) to l_iThrow\r
+    \r
+    function_return (string(iError)+": "+l_sBuf)\r
+end_function\r
+\r
+// Get system disk info\r
+// argv1 = disk mount point i.e. c:\\r
+// argv2 = "" or "TOTAL", where TOTAL returns free and blank displays used.\r
+function disk_info global string argv string argv2 returns number\r
+    local string l_sSectorsPerCluster l_sBytesPerSector l_sNumberOfFreeClusters l_sTotalNumberOfClusters\r
+    local pointer l_pSectorsPerCluster l_pBytesPerSector l_pNumberOfFreeClusters l_pTotalNumberOfClusters\r
+    local number l_iSectorsPerCluster l_iBytesPerSector l_iNumberOfFreeClusters l_iTotalNumberOfClusters l_iSpace\r
+    \r
+    move 0 to l_iSpace\r
+\r
+    if (argv <> "") begin\r
+        zerotype _DISKDATA1 to l_sSectorsPerCluster\r
+        zerotype _DISKDATA2 to l_sBytesPerSector \r
+        zerotype _DISKDATA3 to l_sNumberOfFreeClusters \r
+        zerotype _DISKDATA4 to l_sTotalNumberOfClusters\r
+\r
+        getaddress of l_sSectorsPerCluster to l_pSectorsPerCluster\r
+        getaddress of l_sBytesPerSector to l_pBytesPerSector\r
+        getaddress of l_sNumberOfFreeClusters to l_pNumberOfFreeClusters\r
+        getaddress of l_sTotalNumberOfClusters to l_pTotalNumberOfClusters\r
+\r
+        showln (GetDiskFreeSpace(argv, l_pSectorsPerCluster, l_pBytesPerSector, l_pNumberOfFreeClusters, l_pTotalNumberOfClusters))\r
+\r
+        getbuff from l_sSectorsPerCluster at DISKDATA1.sectorsPerCluster to l_iSectorsPerCluster\r
+        getbuff from l_sBytesPerSector at DISKDATA2.bytesPerSector to l_iBytesPerSector\r
+        getbuff from l_sNumberOfFreeClusters at DISKDATA3.numberOfFreeClusters to l_iNumberOfFreeClusters\r
+        getbuff from l_sTotalNumberOfClusters at DISKDATA4.totalNumberOfClusters to l_iTotalNumberOfClusters\r
+\r
+        // showln l_iSectorsPerCluster\r
+        // showln l_iBytesPerSector \r
+        // showln l_iNumberOfFreeClusters\r
+        // showln l_iTotalNumberOfClusters\r
+        \r
+        if (argv2 = "TOTAL") calc (l_iSectorsPerCluster*l_iBytesPerSector*l_iTotalNumberOfClusters) to l_iSpace\r
+        else calc (l_iSectorsPerCluster*l_iBytesPerSector*l_iNumberOfFreeClusters) to l_iSpace\r
+    end\r
+    \r
+    function_return l_iSpace\r
+end_function\r
+\r
+// Get system memory usage\r
+function get_mem_usage global returns integer\r
+    local integer l_iThrow l_iPid l_iMem\r
+    local string l_sProcessMemoryCounters\r
+    local pointer l_lpProcessMemoryCounters\r
+    local handle l_hProcess\r
+\r
+    zeroType _PROCESS_MEMORY_COUNTERS to l_sProcessMemoryCounters\r
+    getaddress of l_sProcessMemoryCounters to l_lpProcessMemoryCounters\r
+\r
+    put (length(l_sProcessMemoryCounters)) to l_sProcessMemoryCounters at PROCESS_MEMORY_COUNTERS.cb\r
+\r
+    move (get_process_id(0)) to l_iPid\r
+    move (OpenProcess((PROCESS_VM_READ ior PROCESS_QUERY_INFORMATION),HEXNULL,l_iPid)) to l_hProcess\r
+\r
+    move (GetProcessMemoryInfo(l_hProcess, l_lpProcessMemoryCounters, length(l_sProcessMemoryCounters))) to l_iThrow\r
+    getbuff from l_sProcessMemoryCounters at PROCESS_MEMORY_COUNTERS.WorkingSetSize to l_iMem\r
+    \r
+    // showln l_hProcess " " l_iThrow\r
+    // showln (GetLastError())\r
+    // showln (get_last_error_detail(GetLastError()))\r
+\r
+    function_return l_iMem\r
+end_function\r
+\r
+// Uses Microsofts InternetCanonicalizeUrl functionality\r
+// http:// msdn.microsoft.com/en-us/library/windows/desktop/aa384342%28v=vs.85%29.aspx\r
+// https:// groups.google.com/forum/#!topic/microsoft.public.vb.winapi/0RY8jPsx_14\r
+function urldecode global string argv returns string\r
+    local string l_szUrl l_szBuffer l_szStructBytesRead l_sResult\r
+    local pointer l_lpszUrl l_lpszBuffer l_lpdwBufferLength \r
+    local integer l_iwBufferLength l_iResult l_iDllErr\r
+\r
+    move argv to l_szUrl\r
+    move argv to l_sResult\r
+    \r
+    if (length(l_szUrl) > 0) begin\r
+        zerostring ((length(l_szUrl))+1) to l_szBuffer\r
+        getaddress of l_szUrl to l_lpszUrl\r
+        getaddress of l_szBuffer to l_lpszBuffer\r
+        \r
+        zerotype _STRUCTBYTESREAD to l_szStructBytesRead\r
+        put ((length(l_szBuffer))*4) to l_szStructBytesRead at STRUCTBYTESREAD.integer0   // allow 4 bytes per char to generously allow for any length changes (should be 2)\r
+        getaddress of l_szStructBytesRead to l_lpdwBufferLength\r
+\r
+        move (InternetCanonicalizeUrl(l_lpszUrl, l_lpszBuffer, l_lpdwBufferLength, ICU_NO_ENCODE+ICU_DECODE)) to l_iResult\r
+\r
+        getbuff from l_szStructBytesRead at STRUCTBYTESREAD.integer0 to l_iwBufferLength\r
+\r
+        if (l_iResult <> 1) begin\r
+            move (GetLastError()) to l_iDllErr\r
+            custom_error ERROR_CODE_URLDECODE$ ERROR_MSG_URLDECODE ERROR_DETAIL_GETLASTERROR (get_last_error_detail(l_iDllErr))\r
+        end\r
+        move (cstring(l_szBuffer)) to l_sResult     \r
+    end        \r
+    function_return l_sResult        \r
+end_function\r
+\r
+// Uses Microsofts InternetCanonicalizeUrl functionality\r
+// Only encodes parts before ? and #\r
+function urlencode global string argv returns string\r
+    local string l_szUrl l_szBuffer l_szStructBytesRead l_sResult\r
+    local pointer l_lpszUrl l_lpszBuffer l_lpdwBufferLength \r
+    local integer l_iwBufferLength l_iResult l_iDllErr\r
+\r
+    move argv to l_szUrl\r
+    move argv to l_sResult\r
+    if (length(l_szUrl) > 0) begin\r
+        zerostring ((length(l_szUrl))+1) to l_szBuffer\r
+        getaddress of l_szUrl to l_lpszUrl\r
+        getaddress of l_szBuffer to l_lpszBuffer\r
+        \r
+        zerotype _STRUCTBYTESREAD to l_szStructBytesRead\r
+        put ((length(l_szBuffer))*4) to l_szStructBytesRead at STRUCTBYTESREAD.integer0   // allow 4 bytes per char to generously allow for any length changes (should be 2)\r
+        getaddress of l_szStructBytesRead to l_lpdwBufferLength\r
+\r
+        move (InternetCanonicalizeUrl(l_lpszUrl, l_lpszBuffer, l_lpdwBufferLength, ICU_BROWSER_MODE)) to l_iResult\r
+\r
+        getbuff from l_szStructBytesRead at STRUCTBYTESREAD.integer0 to l_iwBufferLength\r
+\r
+        if (l_iResult <> 1) begin\r
+            move (GetLastError()) to l_iDllErr\r
+            custom_error ERROR_CODE_URLENCODE$ ERROR_MSG_URLENCODE ERROR_DETAIL_GETLASTERROR (get_last_error_detail(l_iDllErr))\r
+        end\r
+        move (cstring(l_szBuffer)) to l_sResult     \r
+    end        \r
+    function_return l_sResult        \r
+end_function\r
+\r
+// Functions to pull windows os version string\r
+function get_os_version global returns string\r
+    local string l_sOsInfo l_sVersion l_sReturn\r
+    local pointer l_pOsInfo\r
+    local integer l_iResult l_iMajor l_iMinor l_iBuild l_iPlatform\r
+    \r
+    move "" to l_sVersion\r
+    \r
+    zerotype _OSVERSIONINFO to  l_sOsInfo\r
+    put (length(l_sOsInfo)) to l_sOsInfo at OSVERSIONINFO.dwOSVersionInfoSize\r
+    getaddress of l_sOsInfo to  l_pOsInfo\r
+    \r
+    move (GetVersionEx(l_pOsInfo)) to l_iResult\r
+    \r
+    if (l_iResult = 1) begin\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwMajorVersion to l_iMajor\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwMinorVersion to l_iMinor\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwBuildNumber to l_iBuild\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwPlatformId to l_iPlatform\r
+        // getbuff from l_sOsInfo at OSVERSIONINFO.szCSDVersion to l_sVersion    !??\r
+        move (cstring(right(l_sOsInfo,128))) to l_sVersion\r
+    end\r
+    \r
+    move ("Windows Version: "+string(l_iMajor)+"."+string(l_iMinor)+" Build: "+string(l_iBuild)+" Platform: "+string(l_iPlatform)+" CSDVersion: "+l_sVersion) to l_sReturn\r
+    \r
+    function_return l_sReturn \r
+end_function\r
+\r
+// Functions to pull windows os version as a numeric value\r
+function get_os_version_numeric global returns number\r
+    local string l_sOsInfo l_sVersion\r
+    local pointer l_pOsInfo\r
+    local integer l_iResult l_iMajor l_iMinor l_iBuild l_iPlatform\r
+    \r
+    move "" to l_sVersion\r
+    \r
+    zerotype _OSVERSIONINFO to  l_sOsInfo\r
+    put (length(l_sOsInfo)) to l_sOsInfo at OSVERSIONINFO.dwOSVersionInfoSize\r
+    getaddress of l_sOsInfo to  l_pOsInfo\r
+    \r
+    move (GetVersionEx(l_pOsInfo)) to l_iResult\r
+    \r
+    if (l_iResult = 1) begin\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwMajorVersion to l_iMajor\r
+        getbuff from l_sOsInfo at OSVERSIONINFO.dwMinorVersion to l_iMinor\r
+    end\r
+    \r
+    function_return (number(l_iMajor)+(number(l_iMinor)/10))\r
+end_function\r
+\r
+// Converts binary to hex or base64 strings and vice versa\r
+function binary_to_string_to_binary global string argv string argv2 string argv3 returns string\r
+    local string l_sData l_sDataDecoded l_sDataSizeDecoded l_sReturn\r
+    local pointer l_pData l_pDataDecoded l_pDataSizeDecoded\r
+    local integer l_iResult l_iDataSize l_iDataSizeDecoded l_iOffset\r
+    \r
+    move argv to l_sData\r
+    move (length(l_sData)) to l_iDataSize\r
+    getaddress of l_sData to l_pData\r
+     \r
+    zerostring ((length(l_sData)*4)+1) to l_sDataDecoded\r
+    getaddress of l_sDataDecoded to l_pDataDecoded\r
+            \r
+    zerotype _DW_TYPE to l_sDataSizeDecoded\r
+    put (length(l_sDataDecoded)) to l_sDataSizeDecoded at DW_TYPE.value\r
+    getaddress of l_sDataSizeDecoded to l_pDataSizeDecoded      \r
+    \r
+    case begin\r
+        case (argv2 = "HEX") begin\r
+            if (argv3 = 0) move (CryptBinaryToString(l_pData, l_iDataSize, CRYPT_STRING_HEX, l_pDataDecoded, l_pDataSizeDecoded)) to l_iResult\r
+            if (argv3 = 1) move (CryptStringToBinary(l_pData, l_iDataSize, CRYPT_STRING_HEX, l_pDataDecoded, l_pDataSizeDecoded, HEXNULL, HEXNULL)) to l_iResult\r
+        end\r
+        case break\r
+        case (argv2 = "BASE64") begin\r
+            if (argv3 = 0) move (CryptBinaryToString(l_pData, l_iDataSize, CRYPT_STRING_BASE64, l_pDataDecoded, l_pDataSizeDecoded)) to l_iResult\r
+            if (argv3 = 1) move (CryptStringToBinary(l_pData, l_iDataSize, CRYPT_STRING_BASE64, l_pDataDecoded, l_pDataSizeDecoded, HEXNULL, HEXNULL)) to l_iResult\r
+        end\r
+        case break\r
+        case else custom_error ERROR_CODE_UNKNOWN_FORMAT$ ERROR_MSG_UNKNOWN_FORMAT argv2\r
+    case end\r
+\r
+    getbuff from l_sDataSizeDecoded at DW_TYPE.value to l_iDataSizeDecoded\r
+\r
+    if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+        showln "ERROR: " (ternary(argv3 = 0, "CryptBinaryToString", "CryptStringToBinary")) " "  l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        showln "DATA = " l_sDataDecoded\r
+        showln "SIZE = " l_iDataSizeDecoded\r
+    end\r
+    else begin\r
+        if (argv3 = 0) move (replaces(character(9),replaces(character(10),replaces(character(13),replaces(character(32),cstring(mid(l_sDataDecoded,l_pDataSizeDecoded-l_iOffset,1+l_iOffset)),""),""),""),"")) to l_sReturn              \r
+        else move (cstring(mid(l_sDataDecoded,l_pDataSizeDecoded-l_iOffset,1+l_iOffset))) to l_sReturn\r
+    end\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+// Convert binary data to hex or base64 \r
+function binary_to_string global string argv string argv2 returns string\r
+    function_return (binary_to_string_to_binary(argv, argv2, 0))\r
+end_function\r
+// Convert hex or base64 strings to binary data\r
+function string_to_binary global string argv string argv2 returns string\r
+    function_return (binary_to_string_to_binary(argv, argv2, 1))\r
+end_function\r
+\r
+// List out cryptographic providers on ms windows\r
+function ms_adv_listproviders global returns integer\r
+    local integer l_i l_iResult l_iType\r
+    local string l_sType l_sName l_sNameSize\r
+    local pointer l_pType l_pName l_pNameSize\r
+\r
+    move -1 to l_i\r
+    repeat\r
+        increment l_i\r
+        \r
+        zerotype _DW_TYPE to l_sType\r
+        getaddress of l_sType to l_pType\r
+        \r
+        zerostring 255 to l_sName\r
+        getaddress of l_sName to l_pName\r
+        \r
+        zerotype _DW_TYPE to l_sNameSize\r
+        put length(l_sName) to l_sNameSize at DW_TYPE.value\r
+        getaddress of l_sNameSize to l_pNameSize\r
+    \r
+        move (CryptEnumProviders(l_i, HEXNULL, 0, l_pType, l_pName, l_pNameSize)) to l_iResult\r
+\r
+        if ((l_iResult <> 1) and (GetLastError() <> 0) and (GetLastError() <> 259)) begin\r
+            showln "ERROR: " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end\r
+        getbuff from l_sType at DW_TYPE.value to l_iType\r
+        \r
+        if (l_iResult = 1) showln l_i ") " l_iType " - '" (cstring(l_sName)) "'"\r
+    until (l_iResult <> 1)\r
+\r
+end_function\r
+\r
+//-------------------------------------------------------------------------\r
+// Classes\r
+//-------------------------------------------------------------------------\r
+\r
+// Object to provide basic implimentations of some popular hash algorithms and encryption\r
+// provided by the Microsoft Cryptographic Provider\r
+//\r
+// Send message methods:\r
+//\r
+//    aquire_context                - Create the context of the Microsoft CSP\r
+//    release_context               - Release the context of the Microsoft CSP\r
+//    import_key <key> <ealg>       - Incomplete/WIP\r
+//    derive_key <psw> <halg> <ealg>- Derives an encryption key provider when supplied\r
+//                                    with a password, a hash algorithm and the required \r
+//                                    encryption.\r
+//    modify_key_iv <iv>            - Set the initilization vector of the key provider\r
+//    modify_key_mode <mode>        - Set the key provider mode E.g. CBC, ECB etc\r
+//    destroy_key                   - Dispose of the current key provider\r
+//\r
+// Get methods:\r
+//    hash_data <data> <halg>       - Returns a hash of the passed data in the specified \r
+//                                    algorithm\r
+//    export_key                    - Returns the current encryption key\r
+//    generate_random_key_iv        - Generates and sets a random initilization vector \r
+//                                    for the key provider\r
+//    encrypt <data>                - Encrypt data\r
+//    decrypt <data>                - Decrypt data\r
+//\r
+// Example usage:\r
+//    \r
+//    object test is an msAdvCrypt\r
+//    end_object\r
+//    string data buf\r
+//    \r
+//    // Generate a hash\r
+//    send aquire_context to test\r
+//    get hash_data of test "MYTEXT" "SHA1" to data\r
+//    send release_context to test\r
+//    showln "HASHED: " (binary_to_string(data,"HEX"))\r
+//    \r
+//    // Encrypt some data\r
+//    send aquire_context to test\r
+//    send derive_key to test "MYPASSWORD" "SHA256" "AES_256"\r
+//    send modify_key_mode to test "CBC"\r
+//    get generate_random_key_iv of test to buf\r
+//    move buf to data\r
+//    get encrypt of test "MYDATA" to buf\r
+//    append data buf\r
+//    send destroy_key to test\r
+//    send release_context to test\r
+//    showln "ENCRYPTED: " (binary_to_string(data,"HEX"))\r
+//    \r
+//    // Decrypt some data\r
+//    send aquire_context to test\r
+//    send derive_key to test "MYPASSWORD" "SHA256" "AES_256"\r
+//    send modify_key_mode to test "CBC"\r
+//    send modify_key_iv to test (mid(data,16,1))\r
+//    get decrypt of test (mid(data,length(data)-16,17)) to data\r
+//    send destroy_key to test\r
+//    send release_context to test\r
+//    showln "DECRYPTED: " data\r
+//    \r
+class msAdvCrypt is an array\r
+    procedure construct_object string argc \r
+        forward send construct_object argc\r
+        \r
+        property handle c_hProv \r
+        property handle c_hHash \r
+        property handle c_hKey\r
+        property string c_sAlg\r
+    end_procedure\r
+\r
+    procedure aquire_context\r
+        local integer l_iResult\r
+        local handle l_hProv\r
+        local string l_shProv\r
+        local pointer l_phProv\r
+        \r
+        zerotype _DW_TYPE to l_shProv\r
+        getaddress of l_shProv to l_phProv\r
+        \r
+        if (get_os_version_numeric() < 5.2) begin\r
+            move (CryptAcquireContext(l_phProv, HEXNULL, MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) to l_iResult\r
+            if (GetLastError() = -2146893802) begin\r
+                move (CryptAcquireContext(l_phProv, HEXNULL, MS_ENH_RSA_AES_PROV_XP, PROV_RSA_AES, CRYPT_NEWKEYSET)) to l_iResult\r
+            end\r
+        end\r
+        else begin\r
+            move (CryptAcquireContext(l_phProv, HEXNULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) to l_iResult\r
+            if (GetLastError() = -2146893802) begin\r
+                move (CryptAcquireContext(l_phProv, HEXNULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_NEWKEYSET)) to l_iResult\r
+            end\r
+        end\r
+        \r
+        if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+            showln "ERROR: CryptAcquireContext " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end\r
+        else begin\r
+            getbuff from l_shProv at DW_TYPE.value to l_hProv\r
+            set c_hProv to l_hProv\r
+        end        \r
+    end_procedure\r
+    \r
+    function make_hash string in_data string in_hashalgorithm returns string\r
+        local integer l_iResult l_iHashSize\r
+        local string l_shHash l_sHash l_sRawString l_sHashSize\r
+        local handle l_hProv l_hHash\r
+        local pointer l_phHash l_pHash l_pRawString l_pHashSize\r
+        \r
+        get c_hProv to l_hProv\r
+        \r
+        if (l_hProv = 0) begin\r
+            custom_error ERROR_CODE_NO_CONTEXT$ ERROR_MSG_NO_CONTEXT\r
+        end\r
+        else begin\r
+            move in_data to l_sRawString\r
+            getaddress of l_sRawString to l_pRawString\r
+            \r
+            zerotype _HCRYPTHASH to l_shHash\r
+            getaddress of l_shHash to l_phHash        \r
+    \r
+            case begin\r
+                case (in_hashalgorithm = "MD5") begin\r
+                    move (CryptCreateHash(l_hProv, CALG_MD5, 0, 0, l_phHash)) to l_iResult\r
+                    zerostring (128/8) to l_sHash\r
+                end\r
+                case break  \r
+                case ((in_hashalgorithm = "SHA1") or (in_HASHalgorithm = "SHA")) begin\r
+                    move (CryptCreateHash(l_hProv, CALG_SHA1, 0, 0, l_phHash)) to l_iResult\r
+                    zerostring (160/8) to l_sHash\r
+                end\r
+                case break\r
+                case (in_hashalgorithm = "SHA256") begin\r
+                    move (CryptCreateHash(l_hProv, CALG_SHA_256, 0, 0, l_phHash)) to l_iResult\r
+                    zerostring (256/8) to l_sHash           \r
+                end\r
+                case break\r
+                case (in_hashalgorithm = "SHA384") begin\r
+                    move (CryptCreateHash(l_hProv, CALG_SHA_384, 0, 0, l_phHash)) to l_iResult\r
+                    zerostring (384/8) to l_sHash           \r
+                end\r
+                case break\r
+                case (in_hashalgorithm = "SHA512") begin\r
+                    move (CryptCreateHash(l_hProv, CALG_SHA_512, 0, 0, l_phHash)) to l_iResult\r
+                    zerostring (512/8) to l_sHash                    \r
+                end\r
+                case break  \r
+                case else begin\r
+                    custom_error ERROR_CODE_UNKNOWN_ALGORITHM$ ERROR_MSG_UNKNOWN_ALGORITHM in_hashalgorithm\r
+                end\r
+            case end        \r
+        \r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: CryptCreateHash " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end\r
+        \r
+            getbuff from l_shHash at HCRYPTHASH.value to l_hHash\r
+            getaddress of l_sHash to l_pHash\r
+        \r
+            move (CryptHashData(l_hHash, l_pRawString, (length(l_sRawString)), 0)) to l_iResult\r
+        \r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: Crypthash_data " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end\r
+        \r
+            zerotype _DW_TYPE to l_sHashSize\r
+            put (length(l_sHash)) to l_sHashSize at DW_TYPE.value\r
+            getaddress of l_sHashSize to l_pHashSize\r
+    \r
+            move (CryptGetHashParam(l_hHash, HP_HASHVAL, l_pHash, l_pHashSize, 0)) to l_iResult\r
+        \r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: CryptGetHashParam " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end    \r
+        \r
+            getbuff from l_sHashSize at DW_TYPE.value to l_iHashSize\r
+\r
+            if (l_iHashSize <> length(l_sHash)) begin\r
+                showln "WARNING: Binary data does not match expected hash size:"\r
+                showln "DATA = " l_sHash\r
+                showln "SIZE = " l_iHashSize " / " (length(l_sHash))\r
+            end        \r
+        end\r
+    \r
+        set c_hHash to l_hHash        \r
+   \r
+        function_return (mid(l_sHash,l_iHashSize,1))\r
+    end_function \r
+        \r
+    procedure destroy_hash\r
+        local integer l_iResult\r
+        local handle l_hHash\r
+        \r
+        get c_hHash to l_hHash\r
+\r
+        if (l_hHash <> 0) begin\r
+            move (CryptDestroyHash(l_hHash)) to l_iResult\r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: Cryptdestroy_hash " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end        \r
+            else set c_hHash to 0\r
+        end        \r
+    end_procedure\r
+\r
+    function hash_data string in_data string in_hashalgorithm returns string\r
+        local integer l_iResult\r
+        local string l_sHash\r
+        \r
+        get make_hash in_data in_hashalgorithm to l_sHash\r
+        send destroy_hash\r
+        \r
+        function_return (cstring(l_sHash))\r
+    end_function \r
+    \r
+    //WIP\r
+    procedure import_key string in_key string in_algorithm\r
+        local integer l_iResult\r
+        local string l_sBlobHeader l_sPlainTextKeyBlob l_shKey\r
+        local handle l_hProv l_hKey\r
+        local pointer l_pPlainTextKeyBlob l_phKey\r
+        \r
+        get c_hProv to l_hProv   \r
+        \r
+        zerotype _BLOBHEADER to l_sBlobHeader \r
+        put PLAINTEXTKEYBLOB to l_sBlobHeader at BLOBHEADER.bType\r
+        put 2 to l_sBlobHeader at BLOBHEADER.bVersion\r
+        put 0 to l_sBlobHeader at BLOBHEADER.Reserved\r
+        \r
+        case begin        \r
+            case (in_algorithm = "DES") put CALG_DES to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "3DES") put CALG_3DES to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "3DES_112") put CALG_3DES_112 to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "AES") put CALG_AES to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "AES_128") put CALG_AES_128 to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "AES_192") put CALG_AES_192 to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "AES_256") put CALG_AES_256 to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "RC2") put CALG_RC2 to l_sBlobHeader at BLOBHEADER.ALG_ID\r
+            case break \r
+            case (in_algorithm = "RC4") put CALG_RC4 to l_sBlobHeader at BLOBHEADER.ALG_ID        \r
+            case break \r
+            case else custom_error ERROR_CODE_UNKNOWN_ALGORITHM$ ERROR_MSG_UNKNOWN_ALGORITHM in_algorithm\r
+        case end\r
+        \r
+        zerotype _PLAINTEXTKEYBLOB to l_sPlainTextKeyBlob\r
+        put l_sBlobHeader to l_sPlainTextKeyBlob at PLAINTEXTKEYBLOB.BLOBHEADER\r
+        put (length(in_key)) to l_sPlainTextKeyBlob at PLAINTEXTKEYBLOB.dwKeySize\r
+        put_string in_key to l_sPlainTextKeyBlob at PLAINTEXTKEYBLOB.rgbKeyData       \r
+        \r
+        getaddress of l_sPlainTextKeyBlob to l_pPlainTextKeyBlob\r
+        \r
+        zerotype _HCRYPTKEY to l_shKey\r
+        getaddress of l_shKey to l_phKey\r
+        \r
+        move (CryptImportKey(l_hProv, l_pPlainTextKeyBlob, length(l_sPlainTextKeyBlob), 0, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+        \r
+        if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+            showln "ERROR: CryptImportKey " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end\r
+            \r
+        getbuff from l_shKey at HCRYPTKEY.value to l_hKey\r
+        \r
+    end_procedure\r
+    \r
+    procedure derive_key string in_data string in_hashalgorithm string in_algorithm\r
+        local integer l_iResult\r
+        local handle l_hProv l_hHash l_hKey\r
+        local string l_sKey l_shKey\r
+        local pointer l_phKey\r
+        \r
+        get c_hProv to l_hProv        \r
+        get make_hash in_data in_hashalgorithm to l_sKey        \r
+        get c_hHash to l_hHash\r
+\r
+        if (l_hHash <> 0) begin\r
+            zerotype _HCRYPTKEY to l_shKey\r
+            getaddress of l_shKey to l_phKey\r
+\r
+            // The default cipher mode to be used depends on the underlying CSP and the algorithm that's being used, but it's generally CBC mode\r
+            case begin\r
+                case (in_algorithm = "DES") move (CryptDeriveKey(l_hProv, CALG_DES, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "3DES") move (CryptDeriveKey(l_hProv, CALG_3DES, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "3DES_112") move (CryptDeriveKey(l_hProv, CALG_3DES_112, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "AES") move (CryptDeriveKey(l_hProv, CALG_AES, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "AES_128") move (CryptDeriveKey(l_hProv, CALG_AES_128, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "AES_192") move (CryptDeriveKey(l_hProv, CALG_AES_192, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "AES_256") move (CryptDeriveKey(l_hProv, CALG_AES_256, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "RC2") move (CryptDeriveKey(l_hProv, CALG_RC2, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case (in_algorithm = "RC4") move (CryptDeriveKey(l_hProv, CALG_RC4, l_hHash, CRYPT_EXPORTABLE, l_phKey)) to l_iResult\r
+                case break \r
+                case else custom_error ERROR_CODE_UNKNOWN_ALGORITHM$ ERROR_MSG_UNKNOWN_ALGORITHM in_algorithm\r
+            case end\r
+            \r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: CryptDeriveKey " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end\r
+            else begin        \r
+                getbuff from l_shKey at HCRYPTKEY.value to l_hKey\r
+                set c_sAlg to in_algorithm\r
+            end\r
+\r
+            set c_hKey to l_hKey\r
+        end\r
+    end_procedure\r
+       \r
+    procedure modify_key_iv string in_iv\r
+        local integer l_iResult l_iBlockSize\r
+        local handle l_hKey\r
+        local string l_sIV l_sAlg\r
+        local pointer l_pIV\r
+        \r
+        get c_hKey to l_hKey\r
+        get c_sAlg to l_sAlg\r
+        \r
+        // Set expected block size in bytes\r
+        case begin\r
+            case (l_sAlg contains "DES") calc (64/8) to l_iBlockSize\r
+            case break         \r
+            case (l_sAlg contains "AES") calc (128/8) to l_iBlockSize\r
+            case break \r
+            case (l_sAlg = "RC2") calc (64/8) to l_iBlockSize\r
+            case break \r
+            case else custom_error ERROR_CODE_INCOMPATIBLE_ALGORITHM$ ERROR_MSG_INCOMPATIBLE_ALGORITHM l_sAlg\r
+        case end\r
+        \r
+        if (length(in_iv) <> l_iBlockSize) custom_error ERROR_CODE_INVALID_BLOCKSIZE$ ERROR_MSG_INVALID_BLOCKSIZE (l_sAlg+"="+string(l_iBlockSize)+" NOT "+string(length(in_iv)))\r
+        \r
+        move in_iv to l_sIV\r
+        getaddress of l_sIV to l_pIV\r
+        \r
+        move (CryptSetKeyParam(l_hKey, KP_IV, l_pIV, 0)) to l_iResult\r
+        \r
+        if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+            showln "ERROR: CryptSetKeyParam " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end        \r
+        \r
+    end_procedure\r
+    \r
+    function generate_random_key_iv returns string\r
+        local integer l_i l_iBlockSize\r
+        local string l_sIV l_sAlg        \r
+     \r
+        get c_sAlg to l_sAlg\r
+        move "" to l_sIV\r
+        \r
+        if ((l_sAlg contains "DES") or (l_sAlg = "RC2")) calc (64/8) to l_iBlockSize\r
+    if (l_sAlg contains "AES") calc (128/8) to l_iBlockSize\r
+        \r
+        for l_i from 1 to l_iBlockSize\r
+            append l_sIV (character(48+random(47)))\r
+        loop\r
+        \r
+        send modify_key_iv l_sIV\r
+        \r
+        function_return l_sIV\r
+    end_function\r
+    \r
+    procedure modify_key_mode string in_mode\r
+        local integer l_iResult\r
+        local handle l_hKey\r
+        local string l_sMode l_sbData\r
+        local pointer l_pbData\r
+        \r
+        get c_hKey to l_hKey\r
+\r
+        case begin\r
+            case (in_mode contains "CBC") move CRYPT_MODE_CBC to l_sMode\r
+            case break\r
+            case (in_mode contains "ECB") move CRYPT_MODE_ECB to l_sMode\r
+            case break\r
+            case (in_mode contains "OFB") move CRYPT_MODE_OFB to l_sMode\r
+            case break\r
+            case (in_mode contains "CFB") move CRYPT_MODE_CFB to l_sMode\r
+            case break\r
+            case (in_mode contains "CTS") move CRYPT_MODE_CTS to l_sMode\r
+            case break            \r
+            case else custom_error ERROR_CODE_UNRECOGNISED_MODE$ ERROR_MSG_UNRECOGNISED_MODE l_sMode        \r
+        case end\r
+        \r
+        zerotype _DW_TYPE to l_sbData\r
+        put l_sMode to l_sbData at DW_TYPE.value\r
+        getaddress of l_sbData to l_pbData       \r
+        \r
+        move (CryptSetKeyParam(l_hKey, KP_MODE, l_pbData, 0)) to l_iResult\r
+        \r
+        if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+            showln "ERROR: CryptSetKeyParam " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end        \r
+    \r
+    end_procedure\r
+    \r
+    function export_key returns string\r
+        local integer l_iResult\r
+        local string l_sData l_sDataSize\r
+        local handle l_hKey\r
+        local pointer l_pData l_pDataSize\r
+        local integer l_iKeyBlobSize l_iDataSize\r
+        \r
+        get c_hKey to l_hKey\r
+        \r
+        if (l_hKey <> 0) begin\r
+            zerotype _PLAINTEXTKEYBLOB to l_sData\r
+            getaddress of l_sData to l_pData\r
+        \r
+            zerotype _DW_TYPE to l_sDataSize\r
+            put (length(l_sData)) to l_sDataSize at DW_TYPE.value\r
+            getaddress of l_sDataSize to l_pDataSize\r
+        \r
+            move (CryptExportKey(l_hKey, 0, PLAINTEXTKEYBLOB, 0, l_pData, l_pDataSize)) to l_iResult\r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: CryptExportKey " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end \r
+        \r
+            getbuff from l_sDataSize at DW_TYPE.value to l_iKeyBlobSize\r
+            getbuff from l_sData at PLAINTEXTKEYBLOB.dwKeySize to l_iDataSize\r
+            move (mid(l_sData,l_iDataSize,13)) to l_sData\r
+            \r
+            if (show_debug_lines) begin\r
+                showln "DEBUG: Key blob Size = " l_iKeyBlobSize        \r
+            end\r
+       end\r
+       function_return l_sData\r
+    end_function\r
+    \r
+    function encrypt_decrypt string in_data integer in_decrypt returns string\r
+        local integer l_iResult l_iDataSize\r
+        local string l_sData l_sDataSize\r
+        local pointer l_pData l_pDataSize \r
+        local handle l_hKey\r
+        \r
+        move in_data to l_sData    \r
+        get c_hKey to l_hKey\r
+        \r
+        zerotype _DW_TYPE to l_sDataSize\r
+        put (length(l_sData)) to l_sDataSize at DW_TYPE.value\r
+        getaddress of l_sDataSize to l_pDataSize                        \r
+        \r
+        move (l_sData+repeat(' ',length(l_sData)*2)) to l_sData\r
+        getaddress of l_sData to l_pData        \r
+        \r
+        if (in_decrypt = 0) move (CryptEncrypt(l_hKey, HEXNULL, HEXTRUE, 0, l_pData, l_pDataSize, length(l_sData))) to l_iResult\r
+        else move (CryptDecrypt(l_hKey, HEXNULL, HEXTRUE, 0, l_pData, l_pDataSize)) to l_iResult             \r
+\r
+        if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+            showln "ERROR: " (ternary(in_decrypt = 0, "CryptEncrypt", "CryptDecrypt")) " " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+        end\r
+        \r
+        getbuff from l_sDataSize at DW_TYPE.value to l_iDataSize\r
+        move (cstring(mid(l_sData,l_iDataSize,1))) to l_sData\r
+        \r
+        function_return l_sData\r
+    end_function\r
+    \r
+    function encrypt string in_data returns string\r
+        local string l_sData\r
+        \r
+        get encrypt_decrypt in_data 0 to l_sData\r
+        function_return l_sData\r
+    end_function\r
+    \r
+    function decrypt string in_data returns string\r
+        local string l_sData\r
+        \r
+        get encrypt_decrypt in_data 1 to l_sData\r
+        function_return l_sData\r
+    end_function\r
+    \r
+    procedure destroy_key\r
+        local integer l_iResult\r
+        local handle l_hKey l_hHash\r
+        \r
+        get c_hKey to l_hKey\r
+        \r
+        if (l_hKey <> 0) begin\r
+            move (CryptDestroyKey(l_hKey)) to l_iResult     \r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: CryptDestroyKey " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))                      \r
+            end  \r
+            else begin\r
+                set c_hKey to 0\r
+                set c_sAlg to ""\r
+            end\r
+        end\r
+        \r
+        get c_hHash to l_hHash\r
+        if (l_hHash <> 0) send destroy_hash        \r
+        \r
+    end_procedure\r
+    \r
+    procedure release_context\r
+        local integer l_iResult\r
+        local handle l_hProv  \r
+        \r
+        get c_hProv to l_hProv\r
+    \r
+        if (l_hProv <> 0) begin    \r
+            move (CryptReleaseContext(l_hProv, 0)) to l_iResult\r
+            if ((l_iResult <> 1) and (GetLastError() <> 0)) begin\r
+                showln "ERROR: Cryptrelease_context " l_iResult " - " (GetLastError()) " - " (get_last_error_detail(GetLastError()))\r
+            end    \r
+            else set c_hProv to 0\r
+        end\r
+        \r
+    end_procedure\r
+    \r
+    procedure destory_object\r
+        local handle l_hProv l_hHash l_hKey\r
+        \r
+        get c_hKey to l_hKey\r
+        if (l_hKey <> 0) send destroy_key\r
+        \r
+        get c_hHash to l_hHash\r
+        if (l_hHash <> 0) send destroy_hash\r
+        \r
+        get c_hProv to l_hProv\r
+        if (l_hProv <> 0) send release_context\r
+             \r
+        forward send destory_object\r
+    end_procedure\r
+        \r
+end_class\r
+\r
+//-------------------------------------------------------------------------\r
+// Functions\r
+//-------------------------------------------------------------------------\r
+\r
+// Used for procedural invocations of hashing and encrypting\r
+object msAdvCrypt_global_obj is an msAdvCrypt\r
+end_object\r
+\r
+// Procedural one-shot use of msAdvCrypt hashing\r
+function msAdvCrypt_hash global string in_data string in_hash returns string\r
+    local string l_sReturn\r
+   \r
+    send aquire_context to msAdvCrypt_global_obj\r
+    get make_hash of msAdvCrypt_global_obj in_data in_hash to l_sReturn\r
+    send destroy_hash to msAdvCrypt_global_obj\r
+    send release_context to msAdvCrypt_global_obj\r
+    \r
+    function_return l_sReturn\r
+end_function\r
+\r
+function sha512_hex global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA512"),'HEX'))\r
+end_function\r
+\r
+function sha512_base64 global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA512"),'BASE64'))\r
+end_function\r
+\r
+function sha384_hex global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA384"),'HEX'))\r
+end_function\r
+\r
+function sha384_base64 global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA384"),'BASE64'))\r
+end_function\r
+\r
+function sha256_hex global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA256"),'HEX'))\r
+end_function\r
+\r
+function sha256_base64 global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA256"),'BASE64'))\r
+end_function\r
+\r
+function sha1_hex global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA1"),'HEX'))\r
+end_function\r
+\r
+function sha1_base64 global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "SHA1"),'BASE64'))\r
+end_function\r
+\r
+function md5_hex global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "MD5"),'HEX'))\r
+end_function\r
+\r
+function md5_base64 global string in_data returns string\r
+    function_return (binary_to_string(msAdvCrypt_hash(in_data, "MD5"),'BASE64'))\r
+end_function\r
+\r
+// Procedural one-shot use of msAdvCrypt AES256 encryption (HEX)\r
+function aes256_hex_enc global string in_data string in_key returns string\r
+    local string l_sReturn l_sBuf\r
+   \r
+    send aquire_context to msAdvCrypt_global_obj\r
+    \r
+    send derive_key to msAdvCrypt_global_obj in_key "SHA256" "AES_256"\r
+    send modify_key_mode to msAdvCrypt_global_obj "CBC"\r
+    \r
+    get generate_random_key_iv of msAdvCrypt_global_obj to l_sBuf    \r
+    move l_sBuf to l_sReturn\r
+    \r
+    get encrypt of msAdvCrypt_global_obj in_data to l_sBuf\r
+    append l_sReturn l_sBuf\r
+    \r
+    send destroy_key to msAdvCrypt_global_obj    \r
+    send release_context to msAdvCrypt_global_obj\r
+    \r
+    function_return (binary_to_string(l_sReturn,"HEX"))\r
+end_function\r
+\r
+// Procedural one-shot use of msAdvCrypt AES256 decryption (HEX)\r
+function aes256_hex_dec global string in_data string in_key returns string\r
+    local string l_sReturn l_sBuf\r
+   \r
+    move (string_to_binary(in_data,"HEX")) to l_sBuf\r
+   \r
+    send aquire_context to msAdvCrypt_global_obj    \r
+    send derive_key to msAdvCrypt_global_obj in_key "SHA256" "AES_256"\r
+    send modify_key_mode to msAdvCrypt_global_obj "CBC"\r
+    \r
+    send modify_key_iv to msAdvCrypt_global_obj (mid(l_sBuf,16,1))\r
+    \r
+    get decrypt of msAdvCrypt_global_obj (mid(l_sBuf,length(l_sBuf)-16,17)) to l_sReturn\r
+    \r
+    send destroy_key to msAdvCrypt_global_obj    \r
+    send release_context to msAdvCrypt_global_obj\r
+    \r
+    function_return l_sReturn\r
+end_function\r