Merge branch 'master' of ssh.ucc.asn.au:tpg/acess2
authorJohn Hodge (sonata) <[email protected]>
Sun, 18 May 2014 00:47:08 +0000 (08:47 +0800)
committerJohn Hodge (sonata) <[email protected]>
Sun, 18 May 2014 00:47:08 +0000 (08:47 +0800)
102 files changed:
.gitignore
.travis.yml
BuildConf/armv7/Makefile.cfg
BuildConf/x86/Makefile.cfg
Externals/core.mk
Externals/curl/Makefile [new file with mode: 0644]
Externals/curl/patches/config.sub.patch [new file with mode: 0644]
Externals/netsurf/Makefile
Externals/netsurf/patches/UNIFIED.patch
KernelLand/Kernel/arch/helpers.h
KernelLand/Kernel/arch/x86_64/mm_virt.c
KernelLand/Kernel/drv/proc.c
KernelLand/Kernel/drvutil_video.c
KernelLand/Kernel/events.c
KernelLand/Kernel/heap.c
KernelLand/Kernel/include/acess.h
KernelLand/Kernel/include/acess_string.h
KernelLand/Kernel/include/apidoc_mainpage.h
KernelLand/Kernel/include/drv_pci.h
KernelLand/Kernel/libc.c
KernelLand/Kernel/threads.c
KernelLand/Modules/Display/BochsGA/bochsvbe.c
KernelLand/Modules/Display/Tegra2Vid/main.c
KernelLand/Modules/Display/VESA/main.c
KernelLand/Modules/IPStack/icmpv6.h
KernelLand/Modules/IPStack/ipv6.h
KernelLand/Modules/IPStack/tcp.c
KernelLand/Modules/IPStack/tcp.h
KernelLand/Modules/Input/Keyboard/main.c
KernelLand/Modules/Interfaces/UDI/Makefile
KernelLand/Modules/Interfaces/UDI/main.c
KernelLand/Modules/Interfaces/UDI/trans/gfx.c [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/trans/gfx.udic [new file with mode: 0644]
KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt [new file with mode: 0644]
Makefile
Tools/NetTest/Makefile
Tools/NetTest_Runner/Makefile
Tools/NetTest_Runner/include/tests.h
Tools/NetTest_Runner/main.c
Tools/NetTest_Runner/net.c
Tools/NetTest_Runner/stack.c
Tools/NetTest_Runner/test_tcp.c
Tools/nativelib/Makefile
Tools/nativelib/include/threads_int.h
UDI/drivers/gfx_bochs/bochsga_common.h [new file with mode: 0644]
UDI/drivers/gfx_bochs/bochsga_core.c [new file with mode: 0644]
UDI/drivers/gfx_bochs/bochsga_engines.h [new file with mode: 0644]
UDI/drivers/gfx_bochs/bochsga_pio.h [new file with mode: 0644]
UDI/drivers/gfx_bochs/udiprops.txt [new file with mode: 0644]
UDI/drivers/helpers.h [new file with mode: 0644]
UDI/drivers/helpers_gfx.h [new file with mode: 0644]
UDI/gfx_spec_issues.txt [new file with mode: 0644]
UDI/include/udi.h
UDI/include/udi_gfx.h [new file with mode: 0644]
Usermode/Applications/axwin4_src/Notes.txt [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/IWindow.cpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/Makefile [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/compositor.cpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/include/CConfig.hpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/include/IRegion.hpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/include/IVideo.hpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/include/IWindow.hpp [new file with mode: 0644]
Usermode/Applications/axwin4_src/Server/main.cpp [new file with mode: 0644]
Usermode/Applications/gui_terminal_src/vt100.c
Usermode/Applications/init_src/main.c
Usermode/Applications/irc_src/Makefile
Usermode/Applications/irc_src/common.h [new file with mode: 0644]
Usermode/Applications/irc_src/input.c [new file with mode: 0644]
Usermode/Applications/irc_src/input.h [new file with mode: 0644]
Usermode/Applications/irc_src/main.c
Usermode/Applications/irc_src/message.h [new file with mode: 0644]
Usermode/Applications/irc_src/pseudo_curses.c [new file with mode: 0644]
Usermode/Applications/irc_src/pseudo_curses.h [new file with mode: 0644]
Usermode/Applications/irc_src/server.c [new file with mode: 0644]
Usermode/Applications/irc_src/server.h [new file with mode: 0644]
Usermode/Applications/irc_src/window.c [new file with mode: 0644]
Usermode/Applications/irc_src/window.h [new file with mode: 0644]
Usermode/Libraries/Makefile.tpl
Usermode/Libraries/acess.ld_src/Makefile
Usermode/Libraries/crt0.o_src/Makefile
Usermode/Libraries/ld-acess.so_src/arch/x86_64.asm.h
Usermode/Libraries/libc.so_src/TEST_strtoi.c
Usermode/Libraries/libc.so_src/ctype.c
Usermode/Libraries/libc.so_src/errno.c
Usermode/Libraries/libc.so_src/heap.c
Usermode/Libraries/libc.so_src/include_exp/ctype.h
Usermode/Libraries/libc.so_src/include_exp/errno.enum.h
Usermode/Libraries/libc.so_src/include_exp/stdio.h
Usermode/Libraries/libc.so_src/include_exp/string.h
Usermode/Libraries/libc.so_src/stdio.c
Usermode/Libraries/libc.so_src/string.c
Usermode/Libraries/libc.so_src/strtoi.c
Usermode/Libraries/libm.so_src/include_exp/math.h
Usermode/Libraries/libposix.so_src/Makefile
Usermode/Libraries/libposix.so_src/getopt.c [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/endian.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/getopt.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/regex.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/strings.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/unistd.h
Usermode/Libraries/libposix.so_src/unistd.c

index 7ed9ebe..365eb6c 100644 (file)
@@ -26,6 +26,7 @@ serial.txt
 *.gz
 *.img
 *.vmdk
+*.iso
 SrcDoc/
 APIDoc/
 Usermode/*/*/UTEST/stage
index d39dc5d..52dc032 100644 (file)
@@ -6,4 +6,6 @@ compiler: clang
 #env:
 # - ARCH=host HOST_ARCH=x86 USE_ACPICA=0
 # - ARCH=host HOST_ARCH=x86_64 CC="$CC -m64"
-script: "make utest mtest"
+script:
+ - "make utest-build mtest-build"
+ - "make -k utest-run mtest-run"
index d2f0a0f..a2e4cc5 100644 (file)
@@ -2,6 +2,7 @@
 ARM_CPUNAME = gerneric-armv7
 CC = arm-eabi-gcc -mcpu=$(ARM_CPUNAME)
 AS = arm-eabi-gcc -mcpu=$(ARM_CPUNAME) -c
+CXX = arm-eabi-g++ -mcpu=$(ARM_CPUNAME)
 LD = arm-eabi-ld
 OBJDUMP = arm-eabi-objdump
 DISASM := $(OBJDUMP) -d -S
index 6559146..3989363 100644 (file)
@@ -2,14 +2,14 @@
 # Acess2 Build Configuration
 #
 
-CC = i586-elf-gcc
-CXX = i586-elf-g++
+CC = i686-elf-gcc
+CXX = i686-elf-g++
 #CC = clang -m32
-LD = i586-elf-ld
+LD = i686-elf-ld
 #CC = gcc
 #LD = ld
 AS = nasm
-#OBJDUMP = i586-elf-objdump
+#OBJDUMP = i686-elf-objdump
 OBJDUMP = objdump
 RM = @rm -f
 STRIP = strip
index bc7a5b8..6c23a33 100644 (file)
@@ -73,7 +73,14 @@ $(DIR)/%: patches/%
 
 PATCHED_FILES := $(addprefix $(DIR)/,$(PATCHES))
 
-_patch: $(DIR) $(PATCHED_FILES) $(wildcard patches/UNIFIED.patch)
 ifneq ($(wildcard patches/UNIFIED.patch),)
+$(DIR)/_unified_applied: $(wildcard patches/UNIFIED.patch)
        cd $(DIR) && patch -p1 < ../patches/UNIFIED.patch
+       touch $@
+UNIFIED_TARGET=$(DIR)/_unified_applied
+else
+UNIFIED_TARGET=
 endif
+
+_patch: $(DIR) $(PATCHED_FILES) $(UNIFIED_TARGET)
+
diff --git a/Externals/curl/Makefile b/Externals/curl/Makefile
new file mode 100644 (file)
index 0000000..e0c5eef
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Acess2 External: libcurl
+# - Makefile and patches by John Hodge (thePowersGang)
+#
+
+DEPS := 
+TARBALL_PATTERN := curl-*.tar.bz2
+TARBALL_TO_DIR_L := %.tar.bz2
+TARBALL_TO_DIR_R := %
+PATCHES := config.sub
+CONFIGURE_ARGS = LIBS=-lpsocket
+
+include ../common_automake.mk
+
diff --git a/Externals/curl/patches/config.sub.patch b/Externals/curl/patches/config.sub.patch
new file mode 100644 (file)
index 0000000..8380154
--- /dev/null
@@ -0,0 +1,7 @@
+--- bochs-2.6.2_orig/config.sub        2013-06-17 11:39:39.670720710 +0800
++++ bochs-2.6.2/config.sub     2013-06-17 11:48:09.149384231 +0800
+@@ -1356,2 +1356,3 @@
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
++            | -acess2 \
+             | -aos* | -aros* \
+
index d4140c3..5b69f5d 100644 (file)
@@ -12,7 +12,12 @@ NOBDIR = yes
 
 include ../core.mk
 
-_build:
-       cd $(BDIR) && CC=$(HOST)-gcc TARGET=sdl make
+.PHONY: _check_local_deps
+
+_build: _check_local_deps
+       cd $(BDIR) && CC=$(HOST)-gcc TARGET=framebuffer make
+
+_check_local_deps:
+       @gperf --help >/dev/null || (echo "ERROR: netsurf's build system requires gperf"; false)
 
 
index e945631..f59d7c1 100644 (file)
@@ -108,3 +108,15 @@ diff -ru .orig/netsurf-full-3.0//src/libparserutils-0.1.2/src/utils/vector.c net
  {
        if (vector == NULL || vector->current_item < 0)
                return NULL;
+diff -ru .orig/netsurf-full-3.0//src/libnsfb-0.1.2/Makefile netsurf-full-3.0//src/libnsfb-0.1.0/Makefile
+--- .orig/netsurf-full-3.0//src/libnsfb-0.1.0/Makefile 2013-04-20 02:06:57.000000000 +0800
++++ netsurf-full-3.0//src/libnsfb-0.1.0/Makefile       2013-07-01 22:22:45.246689992 +0800
+@@ -31,5 +31,5 @@
+ # surfaces not detectable via pkg-config 
+ NSFB_ABLE_AVAILABLE := no
+-NSFB_LINUX_AVAILABLE := yes
++NSFB_LINUX_AVAILABLE := no
+ # Flags and setup for each support library
+ NSFB_ABLE_AVAILABLE := no
index 4d85fcb..b478031 100644 (file)
 //  > If the `N` value is greater than `D`, we can set this bit
 #define DEF_DIVMOD(s) Uint##s __divmod##s(Uint##s N, Uint##s D, Uint##s*Rem){\
        Uint##s ret=0,add=1;\
-       while(N>=D&&add) {D<<=1;add<<=1;}\
-       while(add>1){\
-               add>>=1;D>>=1;\
+       while(N/2>=D&&add) {D<<=1;add<<=1;}\
+       while(add>0){\
                if(N>=D){ret+=add;N-=D;}\
+               add>>=1;D>>=1;\
        }\
        if(Rem)*Rem = N;\
        return ret;\
index 4e2968f..3d89ea6 100644 (file)
@@ -301,8 +301,6 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
        const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
        tVAddr  rangeStart = 0;
        tPAddr  expected = CHANGEABLE_BITS;     // CHANGEABLE_BITS is used because it's not a vaild value
-       tVAddr  curPos;
-       Uint    page;
        tPAddr  expected_pml4 = PF_WRITE|PF_USER;       
        tPAddr  expected_pdp = PF_WRITE|PF_USER;        
        tPAddr  expected_pd = PF_WRITE|PF_USER; 
@@ -311,11 +309,12 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
        
        End &= (1L << 48) - 1;
        
-       Start >>= 12;   End >>= 12;
+       Start >>= 12;
+       End >>= 12;
        
-       for(page = Start, curPos = Start<<12;
-               page < End;
-               curPos += 0x1000, page++)
+       // `page` will not overflow, End is 48-12 bits
+       tVAddr  curPos = Start << 12;
+       for(Uint page = Start; page <= End; curPos += 0x1000, page++)
        {
                //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
                //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
@@ -486,7 +485,7 @@ int MM_MapEx(volatile void *VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge)
        
        *ent = PAddr | 3;
 
-       if( (tVAddr)VAddr < USER_MAX )
+       if( (tVAddr)VAddr <= USER_MAX )
                *ent |= PF_USER;
        INVLPG( VAddr );
 
index 03288ae..60bf4dd 100644 (file)
@@ -50,9 +50,8 @@ tVFS_NodeType gSysFS_DirNodeType = {
        .FindDir = SysFS_Comm_FindDir
        };
 tSysFS_Ent     gSysFS_Version_Kernel = {
-       NULL, NULL,     // Nexts
-       &gSysFS_Version,        // Parent
-       {
+       .Parent = &gSysFS_Version,      // Parent
+       .Node = {
                .Inode = 1,     // File #1
                .ImplPtr = NULL,
                .ImplInt = (Uint)&gSysFS_Version_Kernel,        // Self-Link
@@ -61,12 +60,11 @@ tSysFS_Ent  gSysFS_Version_Kernel = {
                .ACLs = &gVFS_ACL_EveryoneRO,
                .Type = &gSysFS_FileNodeType
        },
-       "Kernel"
+       .Name = {"Kernel"}
 };
 tSysFS_Ent     gSysFS_Version = {
-       NULL, NULL,
-       &gSysFS_Root,
-       {
+       .Parent = &gSysFS_Root,
+       .Node = {
                .Size = 1,
                .ImplPtr = &gSysFS_Version_Kernel,
                .ImplInt = (Uint)&gSysFS_Version,       // Self-Link
@@ -75,7 +73,7 @@ tSysFS_Ent    gSysFS_Version = {
                .Flags = VFS_FFLAG_DIRECTORY,
                .Type = &gSysFS_DirNodeType
        },
-       "Version"
+       .Name = {"Version"}
 };
 // Root of the SysFS tree (just used to keep the code clean)
 tSysFS_Ent     gSysFS_Root = {
@@ -86,7 +84,7 @@ tSysFS_Ent    gSysFS_Root = {
                .ImplPtr = &gSysFS_Version,
                .ImplInt = (Uint)&gSysFS_Root   // Self-Link
        },
-       "/"
+       {"/"}
 };
 tDevFS_Driver  gSysFS_DriverInfo = {
        NULL, "system",
index 4343ab6..2bffb1a 100644 (file)
@@ -536,8 +536,6 @@ void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
 {
         int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    y, save_pitch;
-       Uint8   *dest, *src;
 
        // Just a little sanity
        if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
@@ -546,16 +544,21 @@ void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
 //     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
 
        // Set up
-       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
-       src = Buf->CursorSaveBuf;
-       
+       size_t  save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       Uint8   *dst = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
+       const Uint8     *src = Buf->CursorSaveBuf;
+
+       ASSERT(Buf->Framebuffer);
+       ASSERT(src);
+       ASSERT(CheckMem(dst, Buf->CursorRenderH*Buf->Pitch));
+       ASSERT(CheckMem(src, Buf->CursorRenderH*save_pitch));
+
        // Copy each line back
-       for( y = 0; y < Buf->CursorRenderH; y ++ )
+       for( int y = 0; y < Buf->CursorRenderH; y ++ )
        {
-               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
+               memcpy( dst, src, Buf->CursorRenderW * bytes_per_px );
                src += save_pitch;
-               dest += Buf->Pitch;
+               dst += Buf->Pitch;
        }
        
        // Set the cursor as removed
index b0225ef..ec47a16 100644 (file)
@@ -7,8 +7,8 @@
  */
 #define DEBUG  0
 #include <acess.h>
-#include <threads_int.h>
 #include <events.h>
+#include <threads_int.h>
 
 // === CODE ===
 void Threads_PostEvent(tThread *Thread, Uint32 EventMask)
index f7054ea..ba4c9ad 100755 (executable)
@@ -353,6 +353,8 @@ void Heap_Deallocate(const char *File, int Line, void *Ptr)
        // INVLPTR is returned from Heap_Allocate when the allocation
        // size is zero.
        if( Ptr == INVLPTR )    return;
+       // free(NULL) is a no-op
+       if( Ptr == NULL )       return;
        
        // Alignment Check
        if( (tVAddr)Ptr % sizeof(void*) != 0 ) {
index fe1a0f9..de16818 100644 (file)
@@ -85,11 +85,11 @@ extern const char   gsBuildInfo[];
  * \{
  * \todo Move to mm_virt.h
  */
-#define        MM_PFLAG_RO             0x01    // Writes disallowed
-#define        MM_PFLAG_EXEC   0x02    // Allow execution
-#define        MM_PFLAG_NOPAGE 0x04    // Prevent from being paged out
-#define        MM_PFLAG_COW    0x08    // Copy-On-Write
-#define        MM_PFLAG_KERNEL 0x10    // Kernel-Only (Ring0)
+#define        MM_PFLAG_RO     0x01    //!< Writes disallowed
+#define        MM_PFLAG_EXEC   0x02    //!< Allow execution
+#define        MM_PFLAG_NOPAGE 0x04    //!< Prevent from being paged out
+#define        MM_PFLAG_COW    0x08    //!< Copy-On-Write
+#define        MM_PFLAG_KERNEL 0x10    //!< Kernel-Only (Ring0)
 /**
  * \}
  */
@@ -143,7 +143,9 @@ typedef struct sKernelSymbol {
  * \name IRQ hander registration
  * \{
  */
+//! Register a callback for when an IRQ is raised
 extern int     IRQ_AddHandler(int Num, void (*Callback)(int, void*), void *Ptr);
+//! Remove a previously registered IRQ handler
 extern void    IRQ_RemHandler(int Handle);
 /**
  * \}
index 12e9ba4..b640793 100644 (file)
@@ -10,7 +10,7 @@
 #include <stdarg.h>
 
 /**
- * \name Strings
+ * \name String Manipulation
  * \{
  */
 // - stdio.h in userland
@@ -38,6 +38,7 @@ extern unsigned long  strtoul(const char *str, char **end, int base);
 extern signed long long        strtoll(const char *str, char **end, int base);
 extern signed long     strtol(const char *str, char **end, int base);
 
+//! \brief String comparison (case-insensitive)
 extern int     strucmp(const char *Str1, const char *Str2);
 extern int     strpos(const char *Str, char Ch);
 extern int     strpos8(const char *str, Uint32 search);
index 8b5b85f..7a5e427 100644 (file)
@@ -23,6 +23,8 @@
  *    user.
  *  - Drivers for specific types of hardware must behave in the specific
  *    way described here.
+ * - \ref library      "Library Functions"
+ *  - Kernel's version of libc and other helper functions
  * 
  * \page drivers Device Drivers
  * 
index 1032814..bdc8c85 100644 (file)
@@ -82,5 +82,6 @@ extern Uint8  PCI_GetIRQ(tPCIDev id);
 extern Uint32  PCI_GetBAR(tPCIDev id, int BAR);\r
 extern Uint64  PCI_GetValidBAR(tPCIDev id, int BAR, tPCI_BARType BARType);\r
 //extern Uint16        PCI_AssignPort(tPCIDev id, int bar, int count);\r
+//extern void* PCI_MapMemBAR(tPCIDev id, int BAR, tPCI_BARType BARType, size_t* Size, tPAddr* PAddr);\r
 \r
 #endif\r
index 2e08a17..fba3047 100644 (file)
@@ -74,6 +74,7 @@ EXPORT(CheckMem);
 // === CODE ===
 // - Import userland stroi.c file
 #define _LIB_H_
+#define _SysDebug(f,v...)      Log_Debug("libc", f ,## v)
 #include "../../Usermode/Libraries/libc.so_src/strtoi.c"
 
 int ParseInt(const char *string, int *Val)
index 545896c..8762a7c 100644 (file)
@@ -1314,22 +1314,16 @@ void Threads_int_DumpThread(tThread *thread)
  */
 void Threads_DumpActive(void)
 {
-       tThread *thread;
-       tThreadList     *list;
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-        int    i;
-       #endif
-       
        Log("Active Threads: (%i reported)", giNumActiveThreads);
        
        #if SCHEDULER_TYPE == SCHED_RR_PRI
-       for( i = 0; i < MIN_PRIORITY+1; i++ )
+       for( int i = 0; i < MIN_PRIORITY+1; i++ )
        {
-               list = &gaActiveThreads[i];
+               tThreadList *list = &gaActiveThreads[i];
        #else
-               list = &gActiveThreads;
+               tThreadList *list = &gActiveThreads;
        #endif
-               for(thread=list->Head;thread;thread=thread->Next)
+               for(tThread *thread = list->Head; thread; thread = thread->Next)
                {
                        Threads_int_DumpThread(thread);
                        if(thread->Status != THREAD_STAT_ACTIVE)
index a6338ae..7674ed9 100644 (file)
@@ -118,8 +118,15 @@ int BGA_Install(char **Arguments)
        dev = PCI_GetDevice(0x1234, 0x1111, 0);\r
        if(dev == -1)\r
                base = VBE_DISPI_LFB_PHYSICAL_ADDRESS;\r
-       else\r
-               base = PCI_GetBAR(dev, 0);\r
+       else {\r
+               Log_Debug("BGA", "BARs %x,%x,%x,%x,%x,%x",\r
+                       PCI_GetBAR(dev, 0), PCI_GetBAR(dev, 1), PCI_GetBAR(dev, 2),\r
+                       PCI_GetBAR(dev, 3), PCI_GetBAR(dev, 4), PCI_GetBAR(dev, 5));\r
+               base = PCI_GetValidBAR(dev, 0, PCI_BARTYPE_MEM);\r
+               // TODO: Qemu/bochs have MMIO versions of the registers in BAR2\r
+               // - This range is non-indexed\r
+               //mmio_base = PCI_GetValidBAR(dev, 2, PCI_BARTYPE_MEM);\r
+       }\r
 \r
        // Map Framebuffer to hardware address\r
        gBGA_Framebuffer = (void *) MM_MapHWPages(base, 768);   // 768 pages (3Mb)\r
index 20fdb8d..21769bc 100644 (file)
@@ -193,7 +193,7 @@ int Tegra2Vid_IOCtl(tVFS_Node *Node, int ID, void *Data)
        
        switch(ID)
        {
-       BASE_IOCTLS(DRV_TYPE_VIDEO, "PL110", VERSION, csaTegra2Vid_IOCtls);
+       BASE_IOCTLS(DRV_TYPE_VIDEO, "Tegra2", VERSION, csaTegra2Vid_IOCtls);
 
        case VIDEO_IOCTL_SETBUFFORMAT:
                DrvUtil_Video_RemoveCursor( &gTegra2Vid_DrvUtil_BufInfo );
index 32022ef..0af86cb 100644 (file)
 #include <limits.h>\r
 \r
 // === CONSTANTS ===\r
-#define USE_BIOS       1\r
+#ifdef ARCHDIR_is_x86\r
+# define USE_BIOS      1\r
+#else\r
+# define USE_BIOS      0\r
+#endif\r
 #define VESA_DEFAULT_FRAMEBUFFER       (KERNEL_BASE|0xA0000)\r
 #define BLINKING_CURSOR        0\r
 #if BLINKING_CURSOR\r
@@ -33,6 +37,7 @@ size_t        Vesa_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff
  int   Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
 void   Vesa_int_HideCursor(void);\r
 void   Vesa_int_ShowCursor(void);\r
+ int   Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor);\r
 void   Vesa_FlipCursor(void *Arg);\r
 Uint16 VBE_int_GetWord(const tVT_Char *Char);\r
 void   VBE_int_Text_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);\r
@@ -124,6 +129,10 @@ int VBE_int_GetModeList(void)
        \r
        // Allocate Info Block\r
        info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
+       if( info == NULL ) {\r
+               Log_Warning("VBE", "VM8086 allocation error");\r
+               return MODULE_ERR_NOTNEEDED;\r
+       }\r
        // Set Requested Version\r
        memcpy(info->signature, "VBE2", 4);\r
        // Set Registers\r
@@ -361,13 +370,16 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
        case VIDEO_IOCTL_SETBUFFORMAT:\r
                Vesa_int_HideCursor();\r
                ret = gVesa_BufInfo.BufferFormat;\r
-               if(Data)        gVesa_BufInfo.BufferFormat = *(int*)Data;\r
+               if(Data)\r
+                       gVesa_BufInfo.BufferFormat = *(int*)Data;\r
                if(gVesa_BufInfo.BufferFormat == VIDEO_BUFFMT_TEXT)\r
-                       DrvUtil_Video_SetCursor( &gVesa_BufInfo, &gDrvUtil_TextModeCursor );\r
+                       Vesa_int_SetCursor(&gDrvUtil_TextModeCursor);\r
                Vesa_int_ShowCursor();\r
                return ret;\r
        \r
        case VIDEO_IOCTL_SETCURSOR:     // Set cursor position\r
+               if( !CheckMem(Data, sizeof(tVideo_IOCtl_Pos)) )\r
+                       return -EINVAL;\r
                Vesa_int_HideCursor();\r
                giVesaCursorX = ((tVideo_IOCtl_Pos*)Data)->x;\r
                giVesaCursorY = ((tVideo_IOCtl_Pos*)Data)->y;\r
@@ -375,9 +387,7 @@ int Vesa_IOCtl(tVFS_Node *Node, int ID, void *Data)
                return 0;\r
        \r
        case VIDEO_IOCTL_SETCURSORBITMAP:\r
-               if( gpVesaCurMode->flags & FLAG_LFB )\r
-                       DrvUtil_Video_SetCursor( &gVesa_BufInfo, Data );\r
-               return 0;\r
+               return Vesa_int_SetCursor(Data);\r
        }\r
        return 0;\r
 }\r
@@ -607,6 +617,21 @@ void Vesa_int_ShowCursor(void)
        }\r
 }\r
 \r
+int Vesa_int_SetCursor(tVideo_IOCtl_Bitmap *Cursor)\r
+{\r
+       if( !CheckMem(Cursor, sizeof(tVideo_IOCtl_Bitmap)) )\r
+               return -EINVAL;\r
+       \r
+       if( gpVesaCurMode && gpVesaCurMode->flags & FLAG_LFB )\r
+       {\r
+               DrvUtil_Video_SetCursor( &gVesa_BufInfo, Cursor );\r
+       }\r
+       else\r
+       {\r
+       }\r
+       return 0;\r
+}\r
+\r
 /**\r
  * \brief Swaps the text cursor on/off\r
  */\r
index bda70b1..66f6134 100644 (file)
@@ -26,32 +26,32 @@ typedef struct {
        Uint16  RouterLifetime; // Seconds, life time as a default router (wtf does that mean?)
        Uint32  ReachableTime;
        Uint32  RetransTimer;   // Miliseconds, time between transmissions of RAs from this router
-       Uint8   Options[];
+       Uint8   Options[0];
 } PACKED tICMPv6_RA;
 
 typedef struct {
        Uint32  Reserved;
        tIPv6   TargetAddress;
-       Uint8   Options[];
+       Uint8   Options[0];
 } PACKED tICMPv6_NS;
 
 typedef struct {
        Uint32  Flags;
        tIPv6   TargetAddress;
-       Uint8   Options[];
+       Uint8   Options[0];
 } PACKED tICMPv6_NA;
 
 typedef struct {
        Uint32  Reserved;
        tIPv6   TargetAddress;
        tIPv6   DestinationAddress;
-       Uint8   Options[];
+       Uint8   Options[0];
 } PACKED tICMPv6_Redirect;
 
 typedef struct {
        Uint8   Type;   // 1,2
        Uint8   Length; // Length of field in units of 8 bytes (incl header), typically 1
-       Uint8   Address[];
+       Uint8   Address[0];
 } PACKED tICMPv6_Opt_LinkAddr;
 
 typedef struct {
@@ -62,7 +62,7 @@ typedef struct {
        Uint32  ValidLifetime;
        Uint32  PreferredLifetime;
        Uint32  _reserved2;
-       tIPv6   Prefix[];
+       tIPv6   Prefix[0];
 } PACKED tICMPv6_Opt_Prefix;
 
 typedef struct {
@@ -70,7 +70,7 @@ typedef struct {
        Uint8   Length;
        Uint16  _rsvd1;
        Uint32  _rsvd2;
-       Uint8   Data[]; // All or part of the redirected message (not exceeding MTU)
+       Uint8   Data[0];        // All or part of the redirected message (not exceeding MTU)
 } PACKED tICMPv6_Opt_Redirect;
 
 typedef struct {
index 35cd742..fec00f7 100644 (file)
@@ -32,7 +32,7 @@ struct sIPv6Header
        Uint8   HopLimit;
        tIPv6   Source;
        tIPv6   Destination;
-       char    Data[];
+       char    Data[0];
 };
 
 #define IPV6_ETHERNET_ID       0x86DD
index bbf7951..5c65a52 100644 (file)
@@ -18,9 +18,9 @@
 #define TCP_WINDOW_SIZE        0x2000
 #define TCP_RECIEVE_BUFFER_SIZE        0x8000
 #define TCP_DACK_THRESHOLD     4096
-#define TCP_DACK_TIMEOUT       500
+#define TCP_DACK_TIMEOUT       100
 
-#define TCP_DEBUG      0       // Set to non-0 to enable TCP packet logging
+#define TCP_DEBUG      1       // Set to non-0 to enable TCP packet logging
 
 // === PROTOTYPES ===
 void   TCP_Initialise(void);
@@ -28,7 +28,8 @@ void  TCP_StartConnection(tTCPConnection *Conn);
 void   TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data);
 void   TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Header, size_t Length, const void *Data);
 void   TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
-void   TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
+ int   TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length);
+ int   TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
 int    TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length);
 void   TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection);
 void   TCP_int_SendDelayedACK(void *ConnPtr);
@@ -146,10 +147,22 @@ void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Hea
                IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL);
        IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL);
 
-       LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length,
+       #if TCP_DEBUG
+       Log_Log("TCP", "TCP_int_SendPacket: <Local>:%i to [%s]:%i (%i data), Flags = %s%s%s%s%s%s%s%s",
+               ntohs(Header->SourcePort),
                IPStack_PrintAddress(Interface->Type, Dest),
-               ntohs(Header->DestPort)
+               ntohs(Header->DestPort),
+               Length,
+               (Header->Flags & TCP_FLAG_CWR) ? "CWR " : "",
+               (Header->Flags & TCP_FLAG_ECE) ? "ECE " : "",
+               (Header->Flags & TCP_FLAG_URG) ? "URG " : "",
+               (Header->Flags & TCP_FLAG_ACK) ? "ACK " : "",
+               (Header->Flags & TCP_FLAG_PSH) ? "PSH " : "",
+               (Header->Flags & TCP_FLAG_RST) ? "RST " : "",
+               (Header->Flags & TCP_FLAG_SYN) ? "SYN " : "",
+               (Header->Flags & TCP_FLAG_FIN) ? "FIN " : ""
                );
+       #endif
 
        Header->Checksum = 0;
        Header->Checksum = TCP_int_CalculateChecksum(Interface->Type, Interface->Address, Dest,
@@ -168,7 +181,7 @@ void TCP_int_SendPacket(tInterface *Interface, const void *Dest, tTCPHeader *Hea
        }
 }
 
-void TCP_int_SendRSTTo(tInterface *Interface, void *Address, size_t Length, const tTCPHeader *Header)
+void TCP_int_SendRSTTo(tInterface *Interface, const void *Address, size_t Length, const tTCPHeader *Header)
 {
        tTCPHeader      out_hdr = {0};
        
@@ -244,96 +257,20 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                {
                        // Check that it is coming in on the same interface
                        if(conn->Interface != Interface)        continue;
-
                        // Check Source Port
-                       Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)",
-                               conn->RemotePort, ntohs(hdr->SourcePort));
                        if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
-
                        // Check Source IP
-                       Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
-                               IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
-                       Log_Debug("TCP", "                == Address(%s)",
-                               IPStack_PrintAddress(conn->Interface->Type, Address));
                        if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
                                continue ;
 
                        Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
                        // We have a response!
-                       TCP_INT_HandleConnectionPacket(conn, hdr, Length);
-
-                       return;
+                       if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 )
+                               return;
+                       break ;
                }
 
-               
-               if( hdr->Flags & TCP_FLAG_RST ) {
-                       LOG("RST, ignore");
-                       return ;
-               }
-               else if( hdr->Flags & TCP_FLAG_ACK ) {
-                       LOG("ACK, send RST");
-                       TCP_int_SendRSTTo(Interface, Address, Length, hdr);
-                       return ;
-               }
-               else if( !(hdr->Flags & TCP_FLAG_SYN) ) {
-                       LOG("Other, ignore");
-                       return ;
-               }
-               Log_Log("TCP", "TCP_GetPacket: Opening Connection");
-               
-               // TODO: Check for halfopen max
-               
-               tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD);
-               conn->LocalPort = srv->Port;
-               conn->RemotePort = ntohs(hdr->SourcePort);
-               
-               switch(Interface->Type)
-               {
-               case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
-               case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
-               default:        ASSERTC(Interface->Type,==,4);  return;
-               }
-               
-               conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
-               conn->HighestSequenceRcvd = conn->NextSequenceRcv;
-               conn->NextSequenceSend = rand();
-               conn->LastACKSequence = ntohl( hdr->SequenceNumber );
-               
-               conn->Node.ImplInt = srv->NextID ++;
-               
-               // Hmm... Theoretically, this lock will never have to wait,
-               // as the interface is locked to the watching thread, and this
-               // runs in the watching thread. But, it's a good idea to have
-               // it, just in case
-               // Oh, wait, there is a case where a wildcard can be used
-               // (srv->Interface == NULL) so having the lock is a good idea
-               SHORTLOCK(&srv->lConnections);
-               conn->Server = srv;
-               conn->Prev = srv->ConnectionsTail;
-               if(srv->Connections) {
-                       ASSERT(srv->ConnectionsTail);
-                       srv->ConnectionsTail->Next = conn;
-               }
-               else {
-                       ASSERT(!srv->ConnectionsTail);
-                       srv->Connections = conn;
-               }
-               srv->ConnectionsTail = conn;
-               if(!srv->NewConnections)
-                       srv->NewConnections = conn;
-               VFS_MarkAvaliable( &srv->Node, 1 );
-               SHORTREL(&srv->lConnections);
-               Semaphore_Signal(&srv->WaitingConnections, 1);
-
-               // Send the SYN ACK
-               hdr->Flags |= TCP_FLAG_ACK;
-               hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
-               hdr->SequenceNumber = htonl(conn->NextSequenceSend);
-               hdr->DestPort = hdr->SourcePort;
-               hdr->SourcePort = htons(srv->Port);
-               hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4;
-               TCP_SendPacket( conn, hdr, 0, NULL );
-               conn->NextSequenceSend ++;
+               TCP_INT_HandleServerPacket(Interface, srv, Address, hdr, Length);
                return ;
        }
 
@@ -348,13 +285,13 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
                        if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
 
                        // Check Source IP
-                       if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
-                               continue;
-                       if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
-                               continue;
+                       if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
+                               continue ;
 
-                       TCP_INT_HandleConnectionPacket(conn, hdr, Length);
-                       return ;
+                       // Handle or fall through
+                       if( TCP_INT_HandleConnectionPacket(conn, hdr, Length) == 0 )
+                               return ;
+                       break;
                }
        }
        
@@ -366,13 +303,92 @@ void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe
        }
 }
 
+/*
+ * Handle packets in LISTEN state
+ */
+int TCP_INT_HandleServerPacket(tInterface *Interface, tTCPListener *Server, const void *Address, tTCPHeader *Header, size_t Length)
+{
+       if( Header->Flags & TCP_FLAG_RST ) {
+               LOG("RST, ignore");
+               return 0;
+       }
+       else if( Header->Flags & TCP_FLAG_ACK ) {
+               LOG("ACK, send RST");
+               TCP_int_SendRSTTo(Interface, Address, Length, Header);
+               return 0;
+       }
+       else if( !(Header->Flags & TCP_FLAG_SYN) ) {
+               LOG("Other, ignore");
+               return 0;
+       }
+       
+       Log_Log("TCP", "TCP_GetPacket: Opening Connection");
+       
+       // TODO: Check security (a TCP Option)
+       // TODO: Check SEG.PRC 
+       // TODO: Check for halfopen max
+       
+       tTCPConnection *conn = TCP_int_CreateConnection(Interface, TCP_ST_SYN_RCVD);
+       conn->LocalPort = Server->Port;
+       conn->RemotePort = ntohs(Header->SourcePort);
+       
+       switch(Interface->Type)
+       {
+       case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
+       case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
+       default:        ASSERTC(Interface->Type,==,4);  return 0;
+       }
+       
+       conn->NextSequenceRcv = ntohl( Header->SequenceNumber ) + 1;
+       conn->HighestSequenceRcvd = conn->NextSequenceRcv;
+       conn->NextSequenceSend = rand();
+       conn->LastACKSequence = ntohl( Header->SequenceNumber );
+       
+       conn->Node.ImplInt = Server->NextID ++;
+       
+       // Hmm... Theoretically, this lock will never have to wait,
+       // as the interface is locked to the watching thread, and this
+       // runs in the watching thread. But, it's a good idea to have
+       // it, just in case
+       // Oh, wait, there is a case where a wildcard can be used
+       // (Server->Interface == NULL) so having the lock is a good idea
+       SHORTLOCK(&Server->lConnections);
+       conn->Server = Server;
+       conn->Prev = Server->ConnectionsTail;
+       if(Server->Connections) {
+               ASSERT(Server->ConnectionsTail);
+               Server->ConnectionsTail->Next = conn;
+       }
+       else {
+               ASSERT(!Server->ConnectionsTail);
+               Server->Connections = conn;
+       }
+       Server->ConnectionsTail = conn;
+       if(!Server->NewConnections)
+               Server->NewConnections = conn;
+       VFS_MarkAvaliable( &Server->Node, 1 );
+       SHORTREL(&Server->lConnections);
+       Semaphore_Signal(&Server->WaitingConnections, 1);
+
+       // Send the SYN ACK
+       Header->Flags = TCP_FLAG_ACK|TCP_FLAG_SYN;
+       Header->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
+       Header->SequenceNumber = htonl(conn->NextSequenceSend);
+       Header->DestPort = Header->SourcePort;
+       Header->SourcePort = htons(Server->Port);
+       Header->DataOffset = (sizeof(tTCPHeader)/4) << 4;
+       TCP_SendPacket( conn, Header, 0, NULL );
+       conn->NextSequenceSend ++;
+       return 0;
+}
+
 /**
  * \brief Handles a packet sent to a specific connection
  * \param Connection   TCP Connection pointer
  * \param Header       TCP Packet pointer
  * \param Length       Length of the packet
  */
-void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
+int TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
 {
         int    dataLen;
        Uint32  sequence_num;
@@ -381,7 +397,11 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
        // TODO: Check if this needs to be here
        if( Connection->State == TCP_ST_FINISHED ) {
                Log_Log("TCP", "Packet ignored - connection finnished");
-               return ;
+               return 1;
+       }
+       if( Connection->State == TCP_ST_FORCE_CLOSE ) {
+               Log_Log("TCP", "Packet ignored - connection reset");
+               return 1;
        }
        
        // Syncronise sequence values
@@ -432,7 +452,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        if( Header->Flags & TCP_FLAG_ACK )
                        {       
                                Log_Log("TCP", "ACKing SYN-ACK");
-                               Connection->State = TCP_ST_OPEN;
+                               Connection->State = TCP_ST_ESTABLISHED;
                                VFS_MarkFull(&Connection->Node, 0);
                                TCP_INT_SendACK(Connection, "SYN-ACK");
                        }
@@ -447,19 +467,34 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
        
        // SYN-ACK sent, expecting ACK
        case TCP_ST_SYN_RCVD:
+               if( Header->Flags & TCP_FLAG_RST )
+               {
+                       Log_Log("TCP", "RST Received, closing");
+                       Connection->State = TCP_ST_FORCE_CLOSE;
+                       VFS_MarkError(&Connection->Node, 1);
+                       return 0;
+               }
                if( Header->Flags & TCP_FLAG_ACK )
                {
                        // TODO: Handle max half-open limit
                        Log_Log("TCP", "Connection fully opened");
-                       Connection->State = TCP_ST_OPEN;
+                       Connection->State = TCP_ST_ESTABLISHED;
                        VFS_MarkFull(&Connection->Node, 0);
                }
                break;
                
        // --- Established State ---
-       case TCP_ST_OPEN:
+       case TCP_ST_ESTABLISHED:
                // - Handle State changes
                //
+               if( Header->Flags & TCP_FLAG_RST )
+               {
+                       Log_Log("TCP", "Conn %p closed, received RST");
+                       // Error outstanding transactions
+                       Connection->State = TCP_ST_FORCE_CLOSE;
+                       VFS_MarkError(&Connection->Node, 1);
+                       return 0;
+               }
                if( Header->Flags & TCP_FLAG_FIN ) {
                        Log_Log("TCP", "Conn %p closed, recieved FIN", Connection);
                        VFS_MarkError(&Connection->Node, 1);
@@ -467,7 +502,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        TCP_INT_SendACK(Connection, "FIN Received");
                        Connection->State = TCP_ST_CLOSE_WAIT;
                        // CLOSE WAIT requires the client to close
-                       return ;
+                       return 0;
                }
        
                // Check for an empty packet
@@ -475,7 +510,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        if( Header->Flags == TCP_FLAG_ACK )
                        {
                                Log_Log("TCP", "ACK only packet");
-                               return ;
+                               return 0;
                        }
                        // TODO: Is this right? (empty packet counts as one byte)
                        if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv )
@@ -483,7 +518,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        Connection->NextSequenceRcv ++;
                        Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
                        TCP_INT_SendACK(Connection, "Empty");
-                       return ;
+                       return 0;
                }
                
                // NOTES:
@@ -610,7 +645,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        Connection->State = TCP_ST_FIN_WAIT2;
                        Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection);
                        VFS_MarkError(&Connection->Node, 1);
-                       return ;
+                       return 0;
                }
                break;
        
@@ -630,7 +665,7 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
                        Connection->State = TCP_ST_TIME_WAIT;
                        Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
                        VFS_MarkError(&Connection->Node, 1);
-                       return ;
+                       return 0;
                }
                break;
        
@@ -642,12 +677,17 @@ void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Head
        case TCP_ST_FINISHED:
                Log_Log("TCP", "Packets when CLOSED, ignoring");
                break;
+       case TCP_ST_FORCE_CLOSE:
+               Log_Log("TCP", "Packets when force CLOSED, ignoring");
+               return 1;
        
        //default:
        //      Log_Warning("TCP", "Unhandled TCP state %i", Connection->State);
        //      break;
        }
        
+       return 0;
+       
 }
 
 /**
@@ -690,10 +730,15 @@ int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t
 void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
 {
        // Calculate length of contiguous bytes
-       const int       length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
+       const size_t    length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
        Uint32  index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
        size_t  runlength = length;
-       LOG("length=%i, index=0x%x", length, index);
+       LOG("HSR=0x%x,NSR=0x%x", Connection->HighestSequenceRcvd, Connection->NextSequenceRcv);
+       if( Connection->HighestSequenceRcvd == Connection->NextSequenceRcv )
+       {
+               return ;
+       }
+       LOG("length=%u, index=0x%x", length, index);
        for( int i = 0; i < length; i ++ )
        {
                 int    bit = index % 8;
@@ -867,6 +912,7 @@ tTCPConnection *TCP_int_CreateConnection(tInterface *Interface, enum eTCPConnect
        Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name);
        #endif
        
+       conn->HighestSequenceRcvd = 0;
        #if CACHE_FUTURE_PACKETS_IN_BYTES
        // Future recieved data (ahead of the expected sequence number)
        conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection);
@@ -1116,7 +1162,8 @@ tVFS_Node *TCP_Client_Init(tInterface *Interface)
        conn->Server = NULL;
        conn->Prev = NULL;
        conn->Next = gTCP_OutbountCons;
-       gTCP_OutbountCons->Prev = conn;
+       if(gTCP_OutbountCons)
+               gTCP_OutbountCons->Prev = conn;
        gTCP_OutbountCons = conn;
        SHORTREL(&glTCP_OutbountCons);
 
@@ -1133,13 +1180,14 @@ size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe
        tTCPConnection  *conn = Node->ImplPtr;
        size_t  len;
        
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+       ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
        LOG("conn = %p {State:%i}", conn, conn->State);
        
        // If the connection has been closed (state > ST_OPEN) then clear
        // any stale data in the buffer (until it is empty (until it is empty))
-       if( conn->State > TCP_ST_OPEN )
+       if( conn->State > TCP_ST_ESTABLISHED )
        {
+               LOG("Connection closed");
                Mutex_Acquire( &conn->lRecievedPackets );
                len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
                Mutex_Release( &conn->lRecievedPackets );
@@ -1235,7 +1283,7 @@ size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void
 //     #endif
        
        // Don't allow a write to a closed connection
-       if( conn->State > TCP_ST_OPEN ) {
+       if( conn->State > TCP_ST_ESTABLISHED ) {
                VFS_MarkError(Node, 1);
                errno = 0;
                LEAVE('i', -1);
@@ -1394,7 +1442,7 @@ void TCP_Client_Close(tVFS_Node *Node)
        }
        Node->ReferenceCount --;
        
-       if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN )
+       if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_ESTABLISHED )
        {
                packet.SourcePort = htons(conn->LocalPort);
                packet.DestPort = htons(conn->RemotePort);
@@ -1416,10 +1464,14 @@ void TCP_Client_Close(tVFS_Node *Node)
                Log_Warning("TCP", "Closing connection that was never opened");
                TCP_int_FreeTCB(conn);
                break;
+       case TCP_ST_FORCE_CLOSE:
+               conn->State = TCP_ST_FINISHED;
+               TCP_int_FreeTCB(conn);
+               break;
        case TCP_ST_CLOSE_WAIT:
                conn->State = TCP_ST_LAST_ACK;
                break;
-       case TCP_ST_OPEN:
+       case TCP_ST_ESTABLISHED:
                conn->State = TCP_ST_FIN_WAIT1;
                while( conn->State == TCP_ST_FIN_WAIT1 )
                        Threads_Yield();
index 43828f1..0e260fc 100644 (file)
@@ -94,7 +94,7 @@ enum eTCPConnectionState
        TCP_ST_SYN_SENT,        // 1 - SYN sent by local, waiting for SYN-ACK
        TCP_ST_SYN_RCVD,        // 2 - SYN recieved, SYN-ACK sent
        
-       TCP_ST_OPEN,            // 3 - Connection open
+       TCP_ST_ESTABLISHED,     // 3 - Connection open
        
        // Local Close
        TCP_ST_FIN_WAIT1,       // 4 - FIN sent, waiting for reply (ACK or FIN)
@@ -102,9 +102,10 @@ enum eTCPConnectionState
        TCP_ST_CLOSING,         // 6 - Waiting for ACK of FIN (FIN sent and recieved)
        TCP_ST_TIME_WAIT,       // 7 - Waiting for timeout after local close
        // Remote close
-       TCP_ST_CLOSE_WAIT,      // 8 - FIN recieved, waiting for user to close (error set, wait for node close)
-       TCP_ST_LAST_ACK,        // 9 - FIN sent and recieved, waiting for ACK
-       TCP_ST_FINISHED         // 10 - Essentially closed, all packets are invalid
+       TCP_ST_FORCE_CLOSE,     // 8  - RST recieved, waiting for user close
+       TCP_ST_CLOSE_WAIT,      // 9  - FIN recieved, waiting for user to close (error set, wait for node close)
+       TCP_ST_LAST_ACK,        // 10 - FIN sent and recieved, waiting for ACK
+       TCP_ST_FINISHED         // 11 - Essentially closed, all packets are invalid
 };
 
 struct sTCPConnection
index 377ae30..32688df 100644 (file)
@@ -117,19 +117,16 @@ int Keyboard_IOCtl(tVFS_Node *Node, int Id, void *Data)
  */
 tKeyboard *Keyboard_CreateInstance(int MaxSym, const char *Name)
 {
-       tKeyboard       *ret;
-        int    sym_bitmap_size = (MaxSym + 7)/8;
-        int    string_size = strlen(Name) + 1;
+       size_t  sym_bitmap_size = (MaxSym + 7)/8;
+       size_t  string_size = strlen(Name) + 1;
 
-       ret = malloc( sizeof(tKeyboard) + sym_bitmap_size + string_size );
+       tKeyboard *ret = calloc( 1, sizeof(tKeyboard) + sym_bitmap_size + string_size );
        if( !ret ) {
                return NULL;
        }
-       // Clear
-       memset(ret, 0, sizeof(tKeyboard) + sym_bitmap_size );
        // Set name
-       ret->Name = (char*)ret + sizeof(tKeyboard) + sym_bitmap_size;
-       memcpy(ret->Name, Name, string_size);
+       ret->Name = (char*)( &ret->KeyStates[sym_bitmap_size] );
+       strcpy(ret->Name, Name);
        // Set node and default keymap
        ret->Node = &gKB_DevInfo.RootNode;
        ret->Keymap = &gKeymap_KBDUS;
index 3b1387b..d149bff 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-CPPFLAGS = -I../../../../UDI/include -Iinclude
+CPPFLAGS = -I../../../../UDI/include -Iinclude -D UDI_VERSION=0x101
 
 # - UDI Library Files
 LIB_OBJS := core/logging.o core/strmem.o core/imc.o core/mem.o core/buf.o
index 1c9fc29..1c48008 100644 (file)
@@ -121,10 +121,10 @@ static udi_boolean_t _get_token_bool(const char *str, const char **outstr)
 static udi_index_t _get_token_idx(const char *str, const char **outstr)
 {
        char    *end;
-       int ret = strtol(str, &end, 10);
-       if( ret < 0 || ret > 255 ) {
-               Log_Notice("UDI", "Value '%.*s' out of range for udi_index_t",
-                       end-str, str);
+       unsigned long ret = strtoul(str, &end, 10);
+       if( ret > 255 ) {
+               Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_index_t",
+                       end-str, str, ret);
                *outstr = NULL;
                return 0;
        }
@@ -145,8 +145,8 @@ static udi_ubit16_t _get_token_uint16(const char *str, const char **outstr)
        char    *end;
        unsigned long ret = strtoul(str, &end, 10);
        if( ret > 0xFFFF ) {
-               Log_Notice("UDI", "Value '%.*s' out of range for udi_ubit16_t",
-                       end-str, str);
+               Log_Notice("UDI", "Value '%.*s' (0x%lx) out of range for udi_ubit16_t",
+                       end-str, str, ret);
                *outstr = NULL;
                return 0;
        }
@@ -419,12 +419,14 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
         int    child_bind_index = 0;
         int    device_index = 0;
         int    next_unpop_region = 1;
+       #define IF_ERROR(op)    if(!str){error_hit=1;op;}
        for( int i = 0; i < nLines; i ++ )
        {
                const char *str = udipropsptrs[i];
                if( !*str )
                        continue ;
                 int    sym = _get_token_sym_v(str, &str, true, caUDI_UdipropsNames);
+               //LOG("Processing option '%s'", (sym >= 0 ? caUDI_UdipropsNames[sym] : "ERR"));
                switch(sym)
                {
                case UDIPROPS__properties_version:
@@ -439,7 +441,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                case UDIPROPS__meta: {
                        tUDI_MetaLangRef *ml = &driver_module->MetaLangs[ml_index++];
                        ml->meta_idx = _get_token_idx(str, &str);
-                       if( !str )      continue;
+                       IF_ERROR(continue);
                        ml->interface_name = str;
                        // TODO: May need to trim trailing spaces
                        ml->metalang = UDI_int_GetMetaLangByName(ml->interface_name);
@@ -455,7 +457,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        tUDI_PropMessage *msg = &driver_module->Messages[msg_index++];
                        msg->locale = cur_locale;
                        msg->index = _get_token_uint16(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        msg->string = str;
                        //Log_Debug("UDI", "Message %i/%i: '%s'", msg->locale, msg->index, msg->string);
                        break;
@@ -467,7 +469,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                case UDIPROPS__region:
                        {
                        udi_index_t rgn_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        // Search for region index (just in case internal_bind_ops appears earlier)
                        tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
                        if( rgn_idx > 0 )
@@ -516,7 +518,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                                        rgn->OverrunTime = _get_token_uint32(str, &str);
                                        break;
                                }
-                               if( !str )      break ;
+                               IF_ERROR(break);
                        }
                        break;
                        }
@@ -524,12 +526,13 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        {
                        tUDI_BindOps    *bind = &driver_module->Parents[parent_index++];
                        bind->meta_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        bind->region_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        bind->ops_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        bind->bind_cb_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
                        if( *str ) {
                                // Expected EOL, didn't get it :(
                        }
@@ -541,9 +544,9 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        {
                        // Get region using index
                        udi_index_t meta = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        udi_index_t rgn_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        
                        // Search for region index (just in case the relevant 'region' comes after)
                        tUDI_PropRegion *rgn = &driver_module->RegionTypes[0];
@@ -569,11 +572,11 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        rgn->BindMeta = meta;
                        
                        rgn->PriBindOps = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        rgn->SecBindOps = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        rgn->BindCb = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        if( *str ) {
                                // TODO: Please sir, I want an EOL
                        }
@@ -583,10 +586,11 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        {
                        tUDI_BindOps    *bind = &driver_module->ChildBindOps[child_bind_index++];
                        bind->meta_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        bind->region_idx = _get_token_idx(str, &str);
-                       if( !str )      continue ;
+                       IF_ERROR(continue);
                        bind->ops_idx = _get_token_idx(str, &str);
+                       IF_ERROR(continue);
                        if( *str ) {
                                // Expected EOL, didn't get it :(
                        }
@@ -607,26 +611,27 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        {
                         int    n_attr = 0;
                        // Count properties (and validate)
-                       _get_token_idx(str, &str);      // message
-                       if( !str )      continue;
+                       _get_token_uint16(str, &str);   // message
+                       IF_ERROR(continue);
                        _get_token_idx(str, &str);      // meta
-                       if( !str )      continue;
+                       IF_ERROR(continue);
                        while( *str )
                        {
                                _get_token_str(str, &str, NULL);
-                               if( !str )      break;
+                               IF_ERROR(break);
                                _get_token_sym(str, &str, true, "string", "ubit32", "boolean", "array", NULL);
-                               if( !str )      break;
+                               IF_ERROR(break);
                                _get_token_str(str, &str, NULL);
-                               if( !str )      break;
+                               IF_ERROR(break);
                                n_attr ++;
                        }
                        // Rewind and actually parse
+                       // - Eat the 'device' token and hence reset 'str'
                        _get_token_str(udipropsptrs[i], &str, NULL);
                        
                        tUDI_PropDevSpec *dev = NEW_wA(tUDI_PropDevSpec, Attribs, n_attr);
                        driver_module->Devices[device_index++] = dev;;
-                       dev->MessageNum = _get_token_idx(str, &str);
+                       dev->MessageNum = _get_token_uint16(str, &str);
                        dev->MetaIdx = _get_token_idx(str, &str);
                        dev->nAttribs = n_attr;
                        n_attr = 0;
@@ -634,10 +639,10 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                        {
                                udi_instance_attr_list_t *at = &dev->Attribs[n_attr];
                                _get_token_str(str, &str, at->attr_name);
-                               if( !str )      break;
+                               IF_ERROR(break);
                                at->attr_type = _get_token_sym(str, &str, true,
                                        " ", "string", "array", "ubit32", "boolean", NULL);
-                               if( !str )      break;
+                               IF_ERROR(break);
                                udi_ubit32_t    val;
                                switch( dev->Attribs[n_attr].attr_type )
                                {
@@ -662,7 +667,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                                        UDI_ATTR32_SET(at->attr_value, _get_token_bool(str, &str));
                                        break;
                                }
-                               if( !str )      break;
+                               IF_ERROR(break);
                                n_attr ++;
                        }
                        
@@ -675,7 +680,7 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
        }
        free(udipropsptrs);
        if( error_hit ) {
-               Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (%p), bailing",
+               Log_Error("UDI", "Error encountered while parsing udiprops for '%s' (LoadBase=%p), bailing",
                        driver_module->ModuleName, LoadBase);
                for( int i = 0; i < device_index; i ++ )
                        free(driver_module->Devices[i]);
@@ -688,10 +693,14 @@ tUDI_DriverModule *UDI_int_LoadDriver(void *LoadBase, const udi_init_t *info, co
                free(driver_module);
                return NULL;
        }
+       ASSERTC(device_index, ==, driver_module->nDevices);
 
-       for( int i = 0; i < driver_module->nDevices; i ++ )
+       for( int i = 0; i < driver_module->nDevices; i ++ ) {
+               ASSERT(driver_module);
+               ASSERT(driver_module->Devices[i]);
                driver_module->Devices[i]->Metalang = UDI_int_GetMetaLang(driver_module,
                        driver_module->Devices[i]->MetaIdx);
+       }
        
        // Sort message list
        // TODO: Sort message list
diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx.c b/KernelLand/Modules/Interfaces/UDI/trans/gfx.c
new file mode 100644 (file)
index 0000000..5530e7f
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * trans/gfx.c
+ * - Graphics interface
+ */
+#define DEBUG  1
+#define UDI_VERSION 0x101
+#define UDI_GFX_VERSION 0x101
+#include <udi.h>
+#include <udi_gfx.h>
+#include <acess.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+typedef struct rdata_s
+{
+       
+} rdata_t;
+
+// === PROTOTYPES ===
+// --- Management metalang
+void acessgfx_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
+void acessgfx_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
+void acessgfx_final_cleanup_req(udi_mgmt_cb_t *cb);
+// --- GFX Binding
+void acessgfx_channel_event_ind(udi_channel_event_cb_t *cb);
+void acessgfx_bind_ack(udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status);
+void acessgfx_unbind_ack(udi_gfx_bind_cb_t *cb);
+void acessgfx_set_connector_ack(udi_gfx_state_cb_t *cb);
+void acessgfx_get_connector_ack(udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+void acessgfx_range_connector_ack(udi_gfx_range_cb_t *cb);
+void acessgfx_set_engine_ack(udi_gfx_state_cb_t *cb);
+void acessgfx_get_engine_ack(udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+void acessgfx_range_engine_ack(udi_gfx_range_cb_t *cb);
+void acessgfx_command_ack(udi_gfx_command_cb_t *cb);
+
+// === CODE ===
+void acessgfx_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       
+       // Set up structures that don't need interegating the card to do
+       
+       udi_usage_res(cb);
+}
+
+void acessgfx_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       
+       switch(cb->event)
+       {
+       case UDI_CHANNEL_CLOSED:
+               udi_channel_event_complete(cb);
+               return;
+       case UDI_CHANNEL_BOUND:
+               rdata->active_cb = UDI_GCB(cb);
+               acessgfx_channel_event_ind$bound(cb->params.parent_bound.bind_cb);
+               return;
+       default:
+               // TODO: emit an error of some form?
+               return;
+       }
+}
+
+void acessgfx_channel_event_ind$bound(udi_gfx_bind_cb_t *cb)
+{
+       rdata_t *rdata = UDI_GCB(bind_cb)->context;
+       
+       // request metalanguage-level bind
+       udi_gfx_bind_req(bind_cb)
+       // Continued in acessgfx_bind_ack
+}
+
+void acessgfx_bind_ack(udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status)
+{
+       rdata_t *rdata = UDI_GCB(bind_cb)->context;
+       
+       if( status != UDI_OK ) {
+               // binding failed
+               
+               return ;
+       }
+       
+       // 
+}
+
+// === UDI Bindings ===
+
diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx.udic b/KernelLand/Modules/Interfaces/UDI/trans/gfx.udic
new file mode 100644 (file)
index 0000000..48fe9a1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Acess2 UDI Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * trans/gfx.c
+ * - Graphics interface
+ */
+#define DEBUG  1
+#define UDI_VERSION 0x101
+#define UDI_GFX_VERSION 0x101
+#include <udi.h>
+#include <udi_gfx.h>
+#include <acess.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+typedef struct rdata_s
+{
+       
+} rdata_t;
+
+// === CODE ===
+void usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
+{
+       // Set up structures that don't need interegating the card to do
+       
+}
+
+@GFX_CLIENT channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       udi_gfx_bind_cb_t       *bind_cb = cb->params.parent_bound.bind_cb;
+       switch(cb->event)
+       {
+       case UDI_CHANNEL_CLOSED:
+               return;
+       case UDI_CHANNEL_BOUND:
+               [sockets, engines, status] = udi_gfx_bind_req(bind_cb);
+               if( status != UDI_OK ) {
+                       return;
+               }
+               // allocate a CB
+               [new_cb] = udi_cb_alloc(bind_cb, ACESSGFX_CB_STATE);
+               udi_gfx_state_cb_t *state_cb = new_cb;
+               for( int i = 0; i < engines; i ++ )
+               {
+                       state_cb->subsystem = i;
+                       state_cb->attribute = UDI_GFX_PROP_PIXELFORMAT;
+                       [pixfmt] = udi_gfx_get_engine_req(state_cb);
+                       
+                       // TODO: Annotate udi_gfx_state_cb_t to note values are kept?
+                       state_cb->subsystem = i;
+                       state_cb->attribute = UDI_GFX_PROP_OPERATOR_INDEX;
+                       [count] = udi_gfx_get_engine_req(state_cb);
+                       for( int j = 0; j < count; j ++ )
+                       {
+                               state_cb->attribute = j;
+                               [operator, arg_1, arg_2, arg_3] = udi_gfx_engine_getop_req(state_cb);
+                               Log_Debug("UDIGFX", "%i/%i: %i 0x%x 0x%x 0x%x",
+                                       i, j,
+                                       operator, arg_1, arg_2, arg_3);
+                       }
+               }
+               return;
+       default:
+               // TODO: emit an error of some form?
+               return;
+       }
+}
+
+// === UDI Bindings ===
+
diff --git a/KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt b/KernelLand/Modules/Interfaces/UDI/trans/gfx_plan.txt
new file mode 100644 (file)
index 0000000..b8e4bb9
--- /dev/null
@@ -0,0 +1,12 @@
+
+Upon binding:
+
+1. Enumerate connectors (types and possible inputs)
+2. For all engines that can have their input be -1, get pixel format
+  a. Parse operator list into a tree
+3. Create MIN(n_conns,n_edge) video devices
+  a. Each device represents an edge engine (engine selected on modeset)
+
+Notes:
+- Need to figure out what engine(s) to use as framebuffer, and what ones to use as cursor
+ > Allow user/admin intervention to set these relations (based on an identifier from the driver)
index 0edc983..c3c26c1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -66,15 +66,27 @@ all-install:        install-Filesystem SyscallList ai-user ai-kmode
 clean: clean-kmode clean-user
 install:       install-Filesystem SyscallList install-user install-kmode
 
-utest: $(USRLIBS:%=utest-%)
+utest-build: $(USRLIBS:%=utest-build-%)
+utest-run: $(USRLIBS:%=utest-run-%)
+utest: utest-build utest-run
 
-$(USRLIBS:%=utest-%): utest-%:
+utest-build-%:
        @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src generate_exp
-       @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest -k
+       @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest-build
+utest-run-%:
+       @CC=$(NCC) $(SUBMAKE) -C Usermode/Libraries/$*_src utest-run -k
 
 # TODO: Module tests using DiskTool and NetTest
-mtest:
+mtest: mtest-build mtest-run
        @echo > /dev/null
+mtest-build:
+       # Network
+       @CC=$(NCC) $(SUBMAKE) -C Tools/nativelib
+       @CC=$(NCC) $(SUBMAKE) -C Tools/NetTest
+       @CC=$(NCC) $(SUBMAKE) -C Tools/NetTest_Runner
+mtest-run:
+       @echo "=== Network Module Test ==="
+       @cd Tools && ./nettest_runner
 
 SyscallList: include/syscalls.h
 include/syscalls.h: KernelLand/Kernel/Makefile KernelLand/Kernel/syscalls.lst
index f76c8b4..913a9be 100644 (file)
@@ -23,7 +23,7 @@ L_OBJ = vfs_shim.o nic.o tcpclient.o tcpserver.o helpers.o cmdline_backend.o
 N_OBJ = main.o tap.o mode_cmdline.o
 
 # Compilation Options
-CFLAGS := -Wall -std=gnu99 -g -Werror -O0 -pthread
+CFLAGS := -Wall -std=gnu99 -g -O0 -pthread
 CPPFLAGS := -I include/ -I ../nativelib/include
 K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC) -I ../../Usermode/Libraries/ld-acess.so_src/include_exp/
 LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g -L .. -lpthread -lnativelib
index e957579..59704c7 100644 (file)
@@ -6,7 +6,7 @@ OBJ += link.o
 OBJ += test_arp.o test_tcp.o
 BIN := ../nettest_runner
 
-CFLAGS := -Wall -std=c99
+CFLAGS := -Wall -std=c99 -g
 CPPFLAGS := -Iinclude
 LIBS := 
 
@@ -23,7 +23,7 @@ $(BIN): $(OBJ)
        @echo [CC] -o $@
        @$(CC) $(LINKFLAGS) -o $@ $(OBJ) $(LIBS)
 
-obj/%.o: %.c
+obj/%.o: %.c Makefile
        @mkdir -p $(dir $@)
        @echo [CC] -c -o $@
        @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< -MMD -MP
index a96f388..f6cc135 100644 (file)
@@ -10,6 +10,7 @@
 
 extern bool    Test_ARP_Basic(void);
 extern bool    Test_TCP_Basic(void);
+extern bool    Test_TCP_Reset(void);
 extern bool    Test_TCP_WindowSizes(void);
 
 #endif
index b1d95c1..57ac080 100644 (file)
@@ -27,16 +27,19 @@ int main(int argc, char *argv[])
                Test_ARP_Basic,
                Test_TCP_Basic,
                Test_TCP_WindowSizes,
+               Test_TCP_Reset,
                NULL
                };
 
+       // Truncate the two output files
        // TODO: Move to stack.c
-       FILE    *fp;
-       fp = fopen("stdout.txt", "w");  fclose(fp);
-       fp = fopen("stderr.txt", "w");  fclose(fp);
+       fclose( fopen("stdout.txt", "w") );
+       fclose( fopen("stderr.txt", "w") );
        
        Net_Open(0, "/tmp/acess2net");
 
+        int    n_pass = 0;
+        int    n_fail = 0;
        for(int i = 0; tests[i]; i ++ )
        {
                Stack_AddDevice("/tmp/acess2net", (char[]){TEST_MAC});
@@ -48,18 +51,22 @@ int main(int argc, char *argv[])
                if( Net_Receive(0, 1, &argc, 1000) == 0 )
                        goto teardown;
                
-               if( tests[i]() )
-                       printf("%s: PASS\n", gsTestName);
+               bool    result = tests[i]();
+               
+               printf("%s: %s\n", gsTestName, (result ? "PASS" : "FAIL"));
+               if(result)
+                       n_pass ++;
                else
-                       printf("%s: FAIL\n", gsTestName);
+                       n_fail ++;
        
        teardown:
                Stack_Kill();
        }
        Net_Close(0);
        unlink("/tmp/acess2net");
+       printf("--- All tests done %i pass, %i fail\n", n_pass, n_fail);
 
-       return 0;
+       return n_fail;
 }
 
 void PrintUsage(const char *ProgName)
index 231df50..4cbf3c8 100644 (file)
@@ -9,6 +9,8 @@
 #include <sys/select.h>
 #include "net.h"
 #include <stdint.h>
+#include <unistd.h>    // unlink/...
+#include <sys/time.h>  // gettimeofday
 
 #define CONNECT_TIMEOUT        10*1000
 #define MAX_IFS        4
@@ -145,7 +147,7 @@ size_t Net_Receive(int IfNum, size_t MaxLen, void *DestBuf, unsigned int Timeout
        
        if( Net_int_EnsureConnected(IfNum) && WaitOnFD(If->FD, false, Timeout) )
        {
-               size_t rv = recvfrom(If->FD, DestBuf, MaxLen, 0, &If->addr, &If->addrlen);
+               size_t rv = recvfrom(If->FD, DestBuf, MaxLen, 0, (struct sockaddr*)&If->addr, &If->addrlen);
                Net_int_SavePacket(If, rv, DestBuf);
                return rv;
        }
@@ -160,7 +162,7 @@ void Net_Send(int IfNum, size_t Length, const void *Buf)
        if( !WaitOnFD(If->FD, true, CONNECT_TIMEOUT) )
                return ;
        Net_int_SavePacket(If, Length, Buf);
-       int rv = sendto(If->FD, Buf, Length, 0, &If->addr, If->addrlen);
+       int rv = sendto(If->FD, Buf, Length, 0, (struct sockaddr*)&If->addr, If->addrlen);
        if( rv < 0 )
                perror("Net_Send - send");
 }
index 7d5e261..1a224e8 100644 (file)
@@ -53,6 +53,7 @@ void Stack_AddInterface(const char *Name, int AddrType, const void *Addr, int Ma
                break;
        default:
                assert(AddrType == 4);
+               fprintf(stderr, "Stack_AddInterface: Bad address type %i\n", AddrType);
                exit(1);
        }
 }
@@ -63,14 +64,24 @@ void Stack_AddRoute(int Type, const void *Network, int MaskBits, const void *Nex
 
 void Stack_AddArg(const char *Fmt, ...)
 {
+       if( giNumStackArgs == MAX_ARGS ) {
+               fprintf(stderr, "ERROR: Too many arguments to stack, %i max\n", MAX_ARGS);
+               return ;
+       }
        va_list args;
+       
        va_start(args, Fmt);
        size_t len = vsnprintf(NULL, 0, Fmt, args);
        va_end(args);
+
        char *arg = malloc(len+1);
+       assert(arg);
+
        va_start(args, Fmt);
        vsnprintf(arg, len+1, Fmt, args);
        va_end(args);
+       
+       assert( arg[len] == '\0' );
        gasStackArgs[giNumStackArgs++] = arg;
 }
 
@@ -123,6 +134,10 @@ void Stack_Kill(void)
                kill(giStack_PID, SIGTERM);
                giStack_PID = 0;
        }
+       
+       for( int i = 1; i < giNumStackArgs; i ++ )
+               free(gasStackArgs[i]);
+       giNumStackArgs = 1;
 }
 
 int Stack_SendCommand(const char *Fmt, ...)
index 36942a5..4e4aeb4 100644 (file)
 #include "tcp.h"
 #include <string.h>
 
+#define RX_HEADER \
+       size_t  rxlen, ofs, len; \
+       char rxbuf[MTU]
+#define TEST_HEADER \
+       TEST_SETNAME(__func__);\
+       RX_HEADER
+
 #define TEST_ASSERT_rx()       TEST_ASSERT( rxlen = Net_Receive(0, sizeof(rxbuf), rxbuf, ERX_TIMEOUT) )
 #define TEST_ASSERT_no_rx()    TEST_ASSERT( Net_Receive(0, sizeof(rxbuf), rxbuf, NRX_TIMEOUT) == 0 )
 const int      ERX_TIMEOUT = 1000;     // Expect RX timeout (timeout=failure)
@@ -24,9 +31,7 @@ const size_t  DACK_BYTES = 4096;      // OS PARAM - Threshold for delayed ACKs
 
 bool Test_TCP_Basic(void)
 {
-       TEST_SETNAME(__func__);
-       size_t  rxlen, ofs, len;
-       char rxbuf[MTU];
+       TEST_HEADER;
 
        tTCPConn        testconn = {
                .IFNum = 0, .AF = 4,
@@ -206,20 +211,41 @@ bool Test_TCP_Basic(void)
        return true;
 }
 
+bool Test_TCP_int_OpenConnection(tTCPConn *Conn)
+{
+       RX_HEADER;
+       // >> SYN
+       TCP_SendC(Conn, TCP_SYN, 0, NULL);
+       Conn->LSeq ++;
+       TEST_ASSERT_rx();
+       // << SYN|ACK (save remote sequence number)
+       TCP_SkipCheck_Seq(true);
+       TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, Conn, TCP_SYN|TCP_ACK) );
+       TEST_ASSERT_REL(len, ==, 0);
+       Conn->RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, Conn->AF) + 1;
+       // >> ACK
+       TCP_SendC(Conn, TCP_ACK, 0, NULL);
+       TEST_ASSERT_no_rx();
+       return true;
+}
+
+#if 0
 bool Test_TCP_SYN_RECEIVED(void)
 {
-       TEST_SETNAME(__func__);
+       TEST_HEADER;
+       
        // 1. Get into SYN-RECEIVED
+       TCP_SendC(&testconn, TCP_SYN, 0, NULL);
        
        // 2. Send various non-ACK packets
        return false;
 }
+#endif
 
-bool Test_TCP_WindowSizes(void)
+bool Test_TCP_Reset(void)
 {
-       TEST_SETNAME(__func__);
-       size_t  rxlen, ofs, len;
-       char rxbuf[MTU];
+       TEST_HEADER;
+       
        tTCPConn        testconn = {
                .IFNum = 0,
                .AF = 4,
@@ -231,20 +257,71 @@ bool Test_TCP_WindowSizes(void)
                .RSeq = 0x600,
                .Window = 128
        };
-       char    testdata[152];
-       memset(testdata, 0xAB, sizeof(testdata));
-       
+
        Stack_SendCommand("tcp_echo_server %i", testconn.RPort);
-       // > Open Connection
+
+       // 1. Response in listen-based SYN-RECEIVED
+       // >> SYN
        TCP_SendC(&testconn, TCP_SYN, 0, NULL);
        testconn.LSeq ++;
+       // << SYN|ACK :: Now in SYN-RECEIVED
        TEST_ASSERT_rx();
        TCP_SkipCheck_Seq(true);
        TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_SYN|TCP_ACK) );
        TEST_ASSERT_REL(len, ==, 0);
        testconn.RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, testconn.AF) + 1;
+       // >> RST (not ACK)
+       TCP_SendC(&testconn, TCP_RST, 0, NULL);
+       // << nothing (connection should now be dead)
+       TEST_ASSERT_no_rx();
+       // >> ACK (this should be to a closed conneciton, see LISTEN[ACK] above)
        TCP_SendC(&testconn, TCP_ACK, 0, NULL);
+       // << RST
+       TEST_ASSERT_rx();
+       TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
+       TEST_ASSERT_REL(len, ==, 0);
+       
+       // 2. Response in open-based SYN-RECEIVED? (What is that?)
+       TEST_WARN("TODO: RFC793 pg70 mentions OPEN-based SYN-RECEIVED");
+       
+       testconn.LPort += 1234;
+       // ESTABLISHED[RST] - RFC793:Pg70
+       // 2. Response in ESTABLISHED 
+       TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) );
+       // >> RST
+       TCP_SendC(&testconn, TCP_RST, 0, NULL);
+       // << no response, connection closed
        TEST_ASSERT_no_rx();
+       // >> ACK (LISTEN[ACK])
+       TCP_SendC(&testconn, TCP_ACK, 0, NULL);
+       // << RST
+       TEST_ASSERT_rx();
+       TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
+       TEST_ASSERT_REL(len, ==, 0);
+       
+       return true;
+}
+
+bool Test_TCP_WindowSizes(void)
+{
+       TEST_HEADER;
+       tTCPConn        testconn = {
+               .IFNum = 0,
+               .AF = 4,
+               .LAddr = BLOB(HOST_IP),
+               .RAddr = BLOB(TEST_IP),
+               .LPort = 44359,
+               .RPort = 9,
+               .LSeq = 0x600,
+               .RSeq = 0x600,
+               .Window = 128
+       };
+       char    testdata[152];
+       memset(testdata, 0xAB, sizeof(testdata));
+       
+       Stack_SendCommand("tcp_echo_server %i", testconn.RPort);
+       // > Open Connection
+       TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) );
        
        // 1. Test remote respecting our transmission window (>=1 byte)
        // > Send more data than our RX window
index 1a50d88..8a8fc33 100644 (file)
@@ -19,7 +19,7 @@ KOBJ := $(KOBJ:%.o=obj/_Kernel/%.o)
 OBJ := $(NOBJ) $(LOBJ) $(KOBJ)
 BIN := ../libnativelib.a
 
-CFLAGS := -Wall -std=c99 -Werror
+CFLAGS := -Wall -std=c99
 CPPFLAGS := -I include
 
 
index 7bd91c1..08bb4f7 100644 (file)
@@ -103,12 +103,12 @@ extern int        Threads_int_CreateThread(struct sThread *Thread);
 extern int     Threads_int_ThreadingEnabled(void);
 
 
-extern tThread *Proc_GetCurThread(void);
-extern tThread *Threads_RemActive(void);
-extern void    Threads_AddActive(tThread *Thread);
+extern struct sThread  *Proc_GetCurThread(void);
+extern struct sThread  *Threads_RemActive(void);
+extern void    Threads_AddActive(struct sThread *Thread);
 extern void    Threads_int_WaitForStatusEnd(enum eThreadStatus Status);
-extern int     Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock);
-extern void    Semaphore_ForceWake(tThread *Thread);
+extern int     Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, struct sThread **ListHead, struct sThread **ListTail, tShortSpinlock *Lock);
+extern void    Semaphore_ForceWake(struct sThread *Thread);
 
 extern tThreadIntMutex *Threads_int_MutexCreate(void);
 extern void    Threads_int_MutexDestroy(tThreadIntMutex *Mutex);
diff --git a/UDI/drivers/gfx_bochs/bochsga_common.h b/UDI/drivers/gfx_bochs/bochsga_common.h
new file mode 100644 (file)
index 0000000..b956900
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * UDI Bochs Graphics Driver
+ * By John Hodge (thePowersGang)
+ *
+ * bochsga_common.c
+ * - Common definitions
+ */
+#ifndef _BOCHSGA_COMMON_H_
+#define _BOCHSGA_COMMON_H_
+
+/**
+ * Definitions to match udiprops.txt
+ * \{
+ */
+#define BOCHSGA_META_BUS       1
+#define BOCHSGA_META_GFX       2
+
+#define BOCHSGA_OPS_DEV        1
+#define BOCHSGA_OPS_GFX        2
+
+#define BOCHSGA_CB_BUS_BIND    1
+#define BOCHSGA_CB_GFX_BIND    2
+#define BOCHSGA_CB_GFX_STATE   3
+#define BOCHSGA_CB_GFX_RANGE   4
+#define BOCHSGA_CB_GFX_COMMAND 5
+
+#define BOCHSGA_MSGNUM_PROPUNK 1001
+/**
+ * \}
+ */
+
+#include "bochsga_pio.h"
+#include "bochsga_engines.h"
+
+typedef struct {
+       udi_ubit32_t    width;
+       udi_ubit32_t    height;
+       udi_index_t     op_idx;
+} engine_t;
+
+/**
+ * Region data
+ */
+typedef struct
+{
+       udi_cb_t        *active_cb;
+       struct {
+               udi_index_t     pio_index;
+       } init;
+
+       udi_pio_handle_t        pio_handles[N_PIO];
+       
+       udi_boolean_t   output_enable;
+       struct {
+               udi_ubit32_t    width;
+               udi_ubit32_t    height;
+               udi_ubit8_t     bitdepth;
+               udi_index_t     engine;
+       } outputstate;
+       struct {
+               udi_ubit32_t    max_width;      // 1024 or 1280
+               udi_ubit32_t    max_height;     // 768 or 1024
+       } limits;
+       
+       engine_t        engines[N_ENGINES];
+} rdata_t;
+
+#define BOCHSGA_MIN_WIDTH      360
+#define BOCHSGA_MIN_HEIGHT     240
+
+#endif
+
diff --git a/UDI/drivers/gfx_bochs/bochsga_core.c b/UDI/drivers/gfx_bochs/bochsga_core.c
new file mode 100644 (file)
index 0000000..c851b07
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * UDI Bochs Graphics Driver
+ * By John Hodge (thePowersGang)
+ *
+ * bochsga_core.c
+ * - Core Code
+ */
+#define UDI_VERSION    0x101
+#define UDI_GFX_VERSION        0x101
+#include <udi.h>
+#include <udi_physio.h>
+#include <udi_gfx.h>
+#define DEBUG_ENABLED  1
+#include "../helpers.h"
+#include "../helpers_gfx.h"
+#include "bochsga_common.h"
+
+// --- Management Metalang
+void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
+
+       // TODO: Set up region data     
+
+       udi_usage_res(cb);
+}
+
+void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       udi_instance_attr_list_t *attr_list = cb->attr_list;
+       
+       switch(enumeration_level)
+       {
+       case UDI_ENUMERATE_START:
+       case UDI_ENUMERATE_START_RESCAN:
+               cb->attr_valid_length = attr_list - cb->attr_list;
+               udi_enumerate_ack(cb, UDI_ENUMERATE_OK, BOCHSGA_OPS_GFX);
+               break;
+       case UDI_ENUMERATE_NEXT:
+               udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
+               break;
+       }
+}
+void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
+{
+}
+void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb)
+{
+}
+// ---
+void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb);
+void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status);
+void bochsga_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle);
+void bochsga_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel);
+void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb);
+
+void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->event)
+       {
+       case UDI_CHANNEL_CLOSED:
+               break;
+       case UDI_CHANNEL_BOUND: {
+               rdata->active_cb = gcb;
+               udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
+               udi_bus_bind_req( bus_bind_cb );
+               // continue at bochsga_bus_dev_bus_bind_ack
+               return; }
+       }
+}
+void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
+       udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       // Set up PIO handles
+       rdata->init.pio_index = -1;
+       bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
+       // V V V V
+}
+void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
+{
+       rdata_t *rdata = gcb->context;
+       if( rdata->init.pio_index != -1 )
+       {
+               rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
+       }
+       
+       rdata->init.pio_index ++;
+       if( rdata->init.pio_index < N_PIO )
+       {
+               const struct s_pio_ops  *ops = &bochsga_pio_ops[rdata->init.pio_index];
+               udi_pio_map(bochsga_bus_dev_bind__pio_map, gcb,
+                       ops->regset_idx, ops->base_offset, ops->length,
+                       ops->trans_list, ops->list_length,
+                       UDI_PIO_LITTLE_ENDIAN, 0, 0
+                       );
+               return ;
+       }
+       
+       udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK);
+       // = = = = =
+}
+void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
+{
+}
+void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
+{
+}
+void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
+{
+}
+// ---
+// GFX Provider ops
+void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       // No operation
+}
+void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb)
+{
+       // TODO: ACK bind if nothing already bound
+}
+void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb)
+{
+       // TODO: Release internal state?
+}
+void bochsga_gfx_set_connector_req$pio(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
+{
+       udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t);
+       udi_gfx_set_connector_ack(cb);
+}
+void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               if( rdata->output_enable != !!value )
+               {
+                       rdata->output_enable = !!value;
+                       udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                               rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+                       return ;
+               }
+               udi_gfx_set_connector_ack(cb);
+               return;
+       // Change input engine
+       // - 
+       case UDI_GFX_PROP_INPUT:
+               if( rdata->outputstate.engine != value )
+               {
+                       // Validate
+                       if( !(0 <= value && value <= N_ENGINES) ) {
+                               udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
+                               return ;
+                       }
+                       
+                       // Change saved bitdepth (requires cycling enable)
+                       rdata->outputstate.engine = value;
+                       rdata->outputstate.bitdepth = bochsga_engine_defs[value].bitdepth;
+               }
+               udi_gfx_set_connector_ack(cb);
+               return;
+       // Alter output dimensions
+       case UDI_GFX_PROP_WIDTH:
+               if( value % 8 != 0 ) {
+                       // Qemu doesn't like resolutions not a multiple of 8
+                       return ;
+               }
+               if( !(320 <= value && value <= rdata->limits.max_width) ) {
+                       return ;
+               } 
+               rdata->outputstate.width = value;
+               udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                       rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               if( !(240 <= value && value <= rdata->limits.max_height) ) {
+                       return ;
+               } 
+               rdata->outputstate.height = value;
+               udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                       rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+               return;
+       }
+       CONTIN(bochsga_gfx_set_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
+}
+void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               udi_gfx_get_connector_ack(cb, !!rdata->output_enable);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.bitdepth/8-1);
+               return;
+       case UDI_GFX_PROP_WIDTH:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.width);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.height);
+               return;
+       case UDI_GFX_PROP_CONNECTOR_TYPE:
+               udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN);
+               return;
+       case UDI_GFX_PROP_SIGNAL:
+               udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED);
+               return;
+       }
+       CONTIN(bochsga_gfx_get_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_get_connector_ack(cb, 0);
+}
+void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               // 2 values: 0 and 1
+               gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               // 0--3 with a step of 1
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, 0, 3, 1);
+               return;
+       case UDI_GFX_PROP_WIDTH:
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
+                       BOCHSGA_MIN_WIDTH, rdata->limits.max_width, 8); // qemu restricts to 8 step
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
+                       BOCHSGA_MIN_HEIGHT, rdata->limits.max_height, 8); // step of 8 for neatness
+               return;
+       case UDI_GFX_PROP_CONNECTOR_TYPE:
+               gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN);
+               return;
+       case UDI_GFX_PROP_SIGNAL:
+               gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED);
+               return;
+       }
+       CONTIN(bochsga_gfx_range_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_range_cb_t      *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
+       udi_gfx_range_connector_ack(cb);
+}
+// --- Engine Manipulation ---
+void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_get_engine_ack(cb, 0);
+               return;
+       }
+       
+       engine_t *engine = &rdata->engines[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_WIDTH:
+               engine->width = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               engine->height = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               if( value >= bochsga_engine_defs[cb->subsystem].op_map.op_count ) {
+                       // Bad value
+                       udi_gfx_set_engine_ack(cb);
+                       return;
+               }
+               engine->op_idx = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       }
+       CONTIN(bochsga_gfx_set_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_set_engine_ack(cb);
+}
+void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_get_engine_ack(cb, 0);
+               return;
+       }
+       
+       const engine_t *engine = &rdata->engines[cb->subsystem];
+       const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               udi_gfx_get_engine_ack(cb, 1);
+               return;
+       
+       case UDI_GFX_PROP_INPUT:
+               udi_gfx_get_engine_ack(cb, -1);
+               return;
+       
+       case UDI_GFX_PROP_WIDTH:
+               udi_gfx_get_engine_ack(cb, engine->width);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               udi_gfx_get_engine_ack(cb, engine->height);
+               return;
+       
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               udi_gfx_get_engine_ack(cb, engine->op_idx);
+               return;
+       case UDI_GFX_PROP_OPERATOR_OPCODE:
+       case UDI_GFX_PROP_OPERATOR_ARG_1:
+       case UDI_GFX_PROP_OPERATOR_ARG_2:
+       case UDI_GFX_PROP_OPERATOR_ARG_3:
+               udi_gfx_get_engine_ack(cb, gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
+               return;
+       }
+       CONTIN(bochsga_gfx_get_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_get_engine_ack(cb, 0);
+}
+void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_range_engine_ack(cb);
+               return;
+       }
+       
+       engine_t *engine = &rdata->engines[cb->subsystem];
+       const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1);
+               return;
+       
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               gfxhelpers_return_range_simple(udi_gfx_range_engine_ack, cb, 0, engine->op_idx-1, 1);
+               return;
+       case UDI_GFX_PROP_OPERATOR_OPCODE:
+       case UDI_GFX_PROP_OPERATOR_ARG_1:
+       case UDI_GFX_PROP_OPERATOR_ARG_2:
+       case UDI_GFX_PROP_OPERATOR_ARG_3:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb,
+                       gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
+               return;
+       }
+       CONTIN(bochsga_gfx_range_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
+       udi_gfx_range_engine_ack( cb );
+}
+void bochsga_gfx_command_req(udi_gfx_command_cb_t *cb)
+{
+       // Need to parse the GLX stream
+}
+
+// ====================================================================
+// - Management ops
+udi_mgmt_ops_t bochsga_mgmt_ops = {
+       bochsga_usage_ind,
+       bochsga_enumerate_req,
+       bochsga_devmgmt_req,
+       bochsga_final_cleanup_req
+};
+udi_ubit8_t    bochsga_mgmt_op_flags[4] = {0,0,0,0};
+// - Bus Ops
+udi_bus_device_ops_t   bochsga_bus_dev_ops = {
+       bochsga_bus_dev_channel_event_ind,
+       bochsga_bus_dev_bus_bind_ack,
+       bochsga_bus_dev_bus_unbind_ack,
+       bochsga_bus_dev_intr_attach_ack,
+       bochsga_bus_dev_intr_detach_ack
+};
+udi_ubit8_t    bochsga_bus_dev_ops_flags[5] = {0};
+// - GFX provider ops
+udi_gfx_provider_ops_t bochsga_gfx_ops = {
+       bochsga_gfx_channel_event_ind,
+       bochsga_gfx_bind_req,
+       bochsga_gfx_unbind_req,
+       bochsga_gfx_set_connector_req,
+       bochsga_gfx_set_engine_req,
+       bochsga_gfx_get_connector_req,
+       bochsga_gfx_get_engine_req,
+       bochsga_gfx_range_connector_req,
+       bochsga_gfx_range_engine_req,
+       bochsga_gfx_command_req
+};
+udi_ubit8_t    bochsga_gfx_ops_flags[10] = {0};
+// --
+udi_primary_init_t     bochsga_pri_init = {
+       .mgmt_ops = &bochsga_mgmt_ops,
+       .mgmt_op_flags = bochsga_mgmt_op_flags,
+       .mgmt_scratch_requirement = 0,
+       .enumeration_attr_list_length = 0,
+       .rdata_size = sizeof(rdata_t),
+       .child_data_size = 0,
+       .per_parent_paths = 0
+};
+udi_ops_init_t bochsga_ops_list[] = {
+       {
+               BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
+               0,
+               (udi_ops_vector_t*)&bochsga_bus_dev_ops,
+               bochsga_bus_dev_ops_flags
+       },
+       {
+               BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM,
+               0,
+               (udi_ops_vector_t*)&bochsga_gfx_ops,
+               bochsga_gfx_ops_flags
+       },
+       {0}
+};
+udi_cb_init_t bochsga_cb_init_list[] = {
+       {BOCHSGA_CB_BUS_BIND,    BOCHSGA_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_BIND,    BOCHSGA_META_GFX, UDI_GFX_BIND_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_STATE,   BOCHSGA_META_GFX, UDI_GFX_STATE_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_RANGE,   BOCHSGA_META_GFX, UDI_GFX_RANGE_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_COMMAND, BOCHSGA_META_GFX, UDI_GFX_COMMAND_CB_NUM, 0, 0,NULL},
+       {0}
+};
+const udi_init_t       udi_init_info = {
+       .primary_init_info = &bochsga_pri_init,
+       .ops_init_list = bochsga_ops_list,
+       .cb_init_list = bochsga_cb_init_list,
+};
diff --git a/UDI/drivers/gfx_bochs/bochsga_engines.h b/UDI/drivers/gfx_bochs/bochsga_engines.h
new file mode 100644 (file)
index 0000000..48323d2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 
+ */
+
+#define BOCHSGA_ENGINE_PROP_BUFFER     (UDI_GFX_PROP_CUSTOM+0)
+
+// === CONSTANTS ===
+const gfxhelpers_op_t  bochsga_engine_ops_8bpp[] = {
+};
+const gfxhelpers_op_t  bochsga_engine_ops_32bpp[] = {
+       {UDI_GFX_OPERATOR_RGB,    1,  2,  3},   // #0 Output RGB from ops #1,#2,#3
+       {UDI_GFX_OPERATOR_SEG,    4, 16,  8},   // #1 Extract 8 bits from bit 16 of #4
+       {UDI_GFX_OPERATOR_SEG,    4,  8,  8},   // #2 8 bits from ofs 8 of #4
+       {UDI_GFX_OPERATOR_SEG,    4,  0,  8},   // #3 8 bits from ofs 0 of #4
+       {UDI_GFX_OPERATOR_BUFFER, 5,  6, 32},   // #4 32 bits from buffer #5 ofs #6
+       {UDI_GFX_OPERATOR_ATTR,   0, BOCHSGA_ENGINE_PROP_BUFFER, 0},    // #5 Buffer index
+       {UDI_GFX_OPERATOR_MAD,    7,  8,  9},   // #6 Get offset (#8 * #7 + #9)
+       {UDI_GFX_OPERATOR_ATTR,   0, UDI_GFX_PROP_SOURCE_WIDTH, 0},     // #7 Read buffer width
+       {UDI_GFX_OPERATOR_Y,      0,  0,  0},   // #8 Y coordinate
+       {UDI_GFX_OPERATOR_X,      0,  0,  0}    // #9 X coordinate
+};
+
+typedef struct {
+       udi_ubit8_t     bitdepth;
+       gfxhelpers_op_map_t     op_map;
+} engine_static_t;
+
+const engine_static_t  bochsga_engine_defs[] = {
+       {.bitdepth = 8, .op_map = {ARRAY_COUNT(bochsga_engine_ops_8bpp), bochsga_engine_ops_8bpp}},
+       {.bitdepth = 16},
+       {.bitdepth = 24},
+       {.bitdepth = 32, .op_map = {ARRAY_COUNT(bochsga_engine_ops_8bpp), bochsga_engine_ops_32bpp}},
+};
+#define N_ENGINES      ARRAY_COUNT(bochsga_engine_defs)
diff --git a/UDI/drivers/gfx_bochs/bochsga_pio.h b/UDI/drivers/gfx_bochs/bochsga_pio.h
new file mode 100644 (file)
index 0000000..f5ddf26
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * TODO
+ */
+#ifndef _BOCHSGA_PIO_H_
+#define _BOCHSGA_PIO_H_
+
+udi_pio_trans_t        bochsga_pio_enable[] = {
+       {UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0},
+       };
+
+enum {
+       BOCHSGA_PIO_ENABLE,
+};
+
+const struct s_pio_ops bochsga_pio_ops[] = {
+       [BOCHSGA_PIO_ENABLE] = UDIH_PIO_OPS_ENTRY(bochsga_pio_enable, 0, UDI_PCI_BAR_2, 0x400, 0xB*2),
+//     UDIH_PIO_OPS_ENTRY(bochsga_pio_enable, 0, UDI_PCI_BAR_2, 0x400, 0xB*2),
+       };
+#define N_PIO  (sizeof(bochsga_pio_ops)/sizeof(struct s_pio_ops))
+
+#endif
+
diff --git a/UDI/drivers/gfx_bochs/udiprops.txt b/UDI/drivers/gfx_bochs/udiprops.txt
new file mode 100644 (file)
index 0000000..8b43d5c
--- /dev/null
@@ -0,0 +1,43 @@
+properties_version 0x101
+supplier 1
+contact 2
+name 3
+shortname bochsga
+release 5 1.0
+
+requires udi 0x101
+requires udi_physio 0x101
+requires udi_bridge 0x101
+requires udi_gfx 0x101
+
+meta 1 udi_bridge
+meta 2 udi_gfx
+#meta 3 udi_gio
+
+parent_bind_ops 1 0 1 1        # bridge, rgn 0, ops 1, cb 1
+child_bind_ops 2 0 2   # Provider
+#parent_bind_ops 3 0 2 3       # GIO bound to 3D provider
+
+#enumerates 102 1 1 3  gio_type string software3d
+
+# - Classic non-PCI version
+device 100 1  bus string system  sysbus_io_addr_lo ubit32 0x01CE  sysbus_io_size ubit32 2  sysbys_mem_addr_lo ubit32 0xE0000000 sysbus_mem_size 0x400000
+# - PCI Version (Non-indexed registers at offset 0x500 in BAR2 MMIO)
+device 101 1  bus string pci  pci_vendor_id ubit32 0x1234  pci_device_id ubit32 0x1111  pci_base_class ubit32 0x03  pci_sub_clais ubit32 0x00  pci_prog_if ubit32 0x00
+
+# Messages
+message 1      John Hodge (thePowersGang)
+message 2      [email protected]
+message 3      Bochs Graphics Adapter
+message        5       BochsGA
+message 100    BochsGA ISA Device
+message 101    BochsGA PCI Device
+
+message 1001   "Unknown property passed to %s: %i"
+
+module bochsga
+region 0
+
+# Source-only udiprops
+compile_options -Wall
+source_files bochsga_core.c
diff --git a/UDI/drivers/helpers.h b/UDI/drivers/helpers.h
new file mode 100644 (file)
index 0000000..9b827b3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * UDI Driver helper macros
+ */
+#ifndef _UDI_HELPERS_H_
+#define _UDI_HELPERS_H_
+
+#if DEBUG_ENABLED
+# define DEBUG_OUT(fmt, v...)  udi_debug_printf("%s: "fmt"\n", __func__ ,## v) 
+#else
+# define DEBUG_OUT(...)        do{}while(0)
+#endif
+
+#define ARRAY_COUNT(arr)       (sizeof(arr)/sizeof(arr[0]))
+
+#define __EXPJOIN(a,b) a##b
+#define _EXPJOIN(a,b)  __EXPJOIN(a,b)
+#define _EXPLODE(params...)    params
+#define _ADDGCB(params...)     (udi_cb_t *gcb, params)
+#define CONTIN(suffix, call, args, params)     extern void _EXPJOIN(suffix##$,__LINE__) _ADDGCB params;\
+       call( _EXPJOIN(suffix##$,__LINE__), gcb, _EXPLODE args); } \
+       void _EXPJOIN(suffix##$,__LINE__) _ADDGCB params { \
+       rdata_t *rdata = gcb->context;
+
+/* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */
+#define UDIH_SET_ATTR_BOOLEAN(attr, name, val) \
+               udi_strcpy((attr)->attr_name, (name)); \
+               (attr)->attr_type = UDI_ATTR_BOOLEAN; \
+               (attr)->attr_length = sizeof(udi_boolean_t); \
+               UDI_ATTR32_SET((attr)->attr_value, (val))
+
+#define UDIH_SET_ATTR32(attr, name, val)       \
+               udi_strcpy((attr)->attr_name, (name)); \
+               (attr)->attr_type = UDI_ATTR_UBIT32; \
+               (attr)->attr_length = sizeof(udi_ubit32_t); \
+               UDI_ATTR32_SET((attr)->attr_value, (val))
+
+#define UDIH_SET_ATTR_ARRAY8(attr, name, val, len) \
+               udi_strcpy((attr)->attr_name, (name)); \
+               (attr)->attr_type = UDI_ATTR_ARRAY8; \
+               (attr)->attr_length = (len); \
+               udi_memcpy((attr)->attr_value, (val), (len))
+
+#define UDIH_SET_ATTR_STRING(attr, name, val, len) \
+               udi_strcpy((attr)->attr_name, (name)); \
+               (attr)->attr_type = UDI_ATTR_STRING; \
+               (attr)->attr_length = (len); \
+               udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len))
+#define UDIH_SET_ATTR_STRFMT(attr, name, maxlen, fmt, v...) \
+               udi_strcpy((attr)->attr_name, (name)); \
+               (attr)->attr_type = UDI_ATTR_STRING; \
+               (attr)->attr_length = udi_snprintf((char *)(attr)->attr_value, (maxlen), (fmt) ,## v )
+
+/**
+ * \brief UDI PIO Helpers
+ */
+struct s_pio_ops {
+       udi_pio_trans_t *trans_list;
+       udi_ubit16_t    list_length;
+       udi_ubit16_t    pio_attributes;
+       udi_ubit32_t    regset_idx;
+       udi_ubit32_t    base_offset;
+       udi_ubit32_t    length;
+};
+#define UDIH_PIO_OPS_ENTRY(list, attr, regset, base, len)      {list, ARRAY_COUNT(list), attr, regset, base, len}
+#endif
diff --git a/UDI/drivers/helpers_gfx.h b/UDI/drivers/helpers_gfx.h
new file mode 100644 (file)
index 0000000..f4d9bcf
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * UDI Driver Helper Macros
+ *
+ * GFX-specific helpers
+ */
+#ifndef _HELPERS_GFX_H_
+#define _HELPERS_GFX_H_
+
+typedef struct {
+       udi_index_t     op;
+       udi_ubit32_t    arg_1;
+       udi_ubit32_t    arg_2;
+       udi_ubit32_t    arg_3;
+} gfxhelpers_op_t;
+
+typedef struct {
+       udi_index_t     op_count;
+       const gfxhelpers_op_t   *ops;
+} gfxhelpers_op_map_t;
+
+static inline udi_ubit32_t gfxhelpers_get_engine_op(
+       const gfxhelpers_op_map_t *map, udi_index_t index, udi_index_t prop
+       )
+{
+       if( index >= map->op_count ) {
+               return 0;
+       }
+       switch(prop) {
+       case UDI_GFX_PROP_OPERATOR_OPCODE:      return map->ops[index].op;
+       case UDI_GFX_PROP_OPERATOR_ARG_1:       return map->ops[index].arg_1;
+       case UDI_GFX_PROP_OPERATOR_ARG_2:       return map->ops[index].arg_2;
+       case UDI_GFX_PROP_OPERATOR_ARG_3:       return map->ops[index].arg_3;
+       }
+       return 0;
+}
+
+static inline void gfxhelpers_return_range_simple(
+       udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb,
+       udi_ubit32_t min, udi_ubit32_t max, udi_ubit32_t step
+       )
+{
+       
+}
+
+static inline void gfxhelpers_return_range_set(
+       udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb,
+       udi_ubit32_t count, ...
+       )
+{
+       
+}
+
+static inline void gfxhelpers_return_range_fixed(
+       udi_gfx_range_connector_ack_op_t *callback, udi_gfx_range_cb_t *cb,
+       udi_ubit32_t value
+       )
+{
+       gfxhelpers_return_range_simple(callback, cb, value, value, 1);
+}
+
+#endif
+
diff --git a/UDI/gfx_spec_issues.txt b/UDI/gfx_spec_issues.txt
new file mode 100644 (file)
index 0000000..e97aea4
--- /dev/null
@@ -0,0 +1,31 @@
+
+
+- Indexed engine operator list (would be better as second set of calls)
+ > Arguments can be passed using custom attributes
+- GL-centric operations (would be better with read_buffer/write_buffer calls)
+- No status returned from operations most
+- Input data format specifcation
+ > Engine operator list specifies it, but in an abstract way (which would require quite smart code to determine)
+ > Doable though, but having a RO property on the engine that notes if it uses a standard pixel format would be nice
+
+
+Engine inspection API:
+> Readonly? Property for number of operations
+ - Readonly because modifcation of the count is not possible
+ - Attributes can be read, so that's your config mechanisim
+> udi_gfx_engine_getop_req(udi_gfx_state_cb_t *cb);
+> udi_gfx_engine_getop_ack(udi_gfx_state_cb_t *cb, udi_ubit8_t operation, udi_ubit32_t arg1, udi_ubit32_t arg2, udi_ubit32_t arg3);
+
+
+Buffer manipulation API:
+
+  struct {
+      udi_cb_t gcb;
+      udi_index_t buffer_idx;
+      udi_ubit32_t offset;
+      udi_buffer_t *data;
+  } udi_gfx_buffer_cb_t;
+
+> udi_gfx_buffer_write_req(udi_gfx_buffer_cb_t *cb);
+> udi_gfx_buffer_write_ack(udi_gfx_buffer_cb_t *cb, udi_status_t status);
+> (OPTIONAL) udi_gfx_buffer_read_req(udi_gfx_buffer_cb_t *cb);
index 50c7077..76dac7b 100644 (file)
@@ -4,6 +4,16 @@
 #ifndef _UDI_H_
 #define _UDI_H_
 
+#ifndef UDI_VERSION
+# error "Please define UDI_VERSION before including"
+#endif
+#if UDI_VERSION < 0x100
+# error "Requesting an unsupported UDI version (pre 1.0)"
+#endif
+#if UDI_VERSION > 0x101
+# error "Requesting an unsupported UDI version (post 1.01)"
+#endif
+
 #include <stdint.h>
 #include <stdarg.h>
 
diff --git a/UDI/include/udi_gfx.h b/UDI/include/udi_gfx.h
new file mode 100644 (file)
index 0000000..d9fbcb2
--- /dev/null
@@ -0,0 +1,563 @@
+/**
+ * Summary: udi_gfx.h
+ * Contains the graphics metalanguage interface details
+ *
+ * Author:
+ *     Marcel Sondaar
+ *
+ * License:
+ *     <Public Domain>
+ *
+ * Source:
+ *     https://www.d-rift.nl/combuster/mos3/?p=viewsource&file=/include/common/udi_gfx.h
+ */
+// note that the specification, and thus, the contents of this file is not fixed.
+#ifndef __UDI_GFX_H__
+#define __UDI_GFX_H__
+#include <udi.h>
+#ifndef UDI_GFX_VERSION
+#error "UDI_GFX_VERSION not defined."
+#elif UDI_GFX_VERSION != 0x101
+#error "UDI_GFX_VERSION not supported."
+#endif
+/**
+ * Enumeration: UDI_GFX_PROP
+ * Lists the various UDI properties
+ */
+// General state properties
+/* Constant: UDI_GFX_PROP_ENABLE
+ *
+ * Valid values:
+ *     0 - disabled
+ *     1 - enabled
+ *
+ * Ranges:
+ *     Hardwired 1, or 0-1
+ *
+ * The connector or engine is enabled (nonzero) or disabled (zero). A disabled
+ * engine forwards all data from the previous stage unmodified. A disabled
+ * connector does not send any data over the connector. Drivers may power down
+ * the physical counterparts of disabled components to preserve power, and users
+ * should expect delays when enabling connectors or components representing
+ * framebuffers. Disabling is however not recommended for sprite layers, which
+ * may repeatedly be enabled and disabled. A disabled component can still have
+ * its state changed, and the driver must complete all commands and other state
+ * changes as expected, regardless of disabled or power state. The valid ranges
+ * reported for this property may be 1 (always enabled) or 0-1 (either enabled
+ * or disabled).
+ */
+#define UDI_GFX_PROP_ENABLE 0
+/* Constant: UDI_GFX_PROP_INPUT
+ *
+ * Valid values:
+ *     Any valid engine ID, provided no dependency cycles are created, or -1
+ *
+ * Ranges:
+ *     Any non-empty set of valid values. Often hardwired.
+ *
+ * Points to the engine that is processed before this unit. In the case of a 
+ * connector, it points to the last engine in a pipeline, and each engine points 
+ * to the next engine in the sequence. A value of -1 indicates a source that 
+ * only yields black pixels. Implementations must not allow cyclic structures. 
+ * Changing this value may reallocate resources, and engines that are no longer 
+ * referenced may lose their data (but not their state) when it is not part of 
+ * any pipeline. If preservation is required, the ENABLE state should be used
+ * instead. Valid ranges includes one or more from the list of engines and -1 
+ * combined. In most cases, this property can not be modified.
+ */
+#define UDI_GFX_PROP_INPUT 1
+/* Constant: UDI_GFX_PROP_WIDTH
+ *
+ * Valid values:
+ *     Any non-zero positive number.
+ *
+ * Ranges:
+ *     Contains at least one valid value. Often only multiples of UNIT_WIDTH
+ *     or a power of two are allowed. May be hardwired.
+ *
+ * Contains the amount of pixels in the horizontal direction. For connectors, 
+ * this is the amount of data pixels rendered horizontally. For engines, this 
+ * is the width in pixels of the image. Pixels requested from an engine outside 
+ * the range (0..width-1) are defined according to the <UDI_GFX_PROP_CLIP> 
+ * property. In some cases, hardware may support only fixed combinations of 
+ * width and height. In such cases, changing the width will also change the 
+ * height to a corresponding valid number. Valid ranges include any values
+ * strictly above zero. For connectors, expect large continuous ranges, large
+ * ranges with a certain modulus, a limited number of fixed values, or a
+ * constant value.
+ */
+#define UDI_GFX_PROP_WIDTH 2
+/* Constant: UDI_GFX_PROP_HEIGHT
+ *
+ * Valid values:
+ *     Any non-zero positive number.
+ *
+ * Ranges:
+ *     Contains at least one valid value. Often only multiples of UNIT_HEIGHT
+ *     or a power of two are allowed. May be hardwired.
+ *
+ * Contains the amount of pixels in the vertical direction. Functions similar
+ * to the width property, but changing it will not alter the width property,
+ * and it's range at any time contains the valid range for the currently
+ * selected width.
+ */
+#define UDI_GFX_PROP_HEIGHT 3
+/* Constant: UDI_GFX_PROP_CUSTOM
+ * The first property index of the driver's custom range. These are not assigned
+ * directly assigned by the UDI specification, but may be specified in the
+ * operator tree.
+ */
+#define UDI_GFX_PROP_CUSTOM 1024
+// engine properties
+/* Constant: UDI_GFX_PROP_CLIP
+ *
+ * Valid values:
+ *     0 - points outside width x height are passed from next stage
+ *     1 - the engine's contents is tiled with size width x height
+ *     2 - points outside the width overflow into the y coordinate
+ *     3 - points outside the height overflow into the x coordinate
+ *
+ * Ranges:
+ *     Hardwired zero for connectors. Any non-empty subset for engines, usually
+ *     hardwired.
+ *
+ * For engines, contains the behaviour for pixels requested outside the width
+ * and height of the engine. Can be either 0 (pass from next stage), 1 (the
+ * coordinates are wrapped modulus the height and width), 2 (the coordinates
+ * overflow onto the next scanline horizontally, and wrap vertically), 3 (the
+ * coordinates overflow onto the next column vertically, and wrap horizontally).
+ * Valid ranges contain one or more of these options. For overlays and sprites,
+ * a value 0 is common. For framebuffers, 2 is the most common value. For
+ * connectors, this property is always 0 since they do not store pixel data
+ */
+#define UDI_GFX_PROP_CLIP 4
+/* Constant: UDI_GFX_PROP_UNIT_WIDTH
+ *
+ * Valid values:
+ *     Any non-zero positive value
+ *
+ * Ranges:
+ *     Any non-empty set of valid values. May be hardwired to 1 for
+ *     framebuffers, or a range of small values for hardware scaling, or any
+ *     larger hardwired number or set for tiling engines.
+ *
+ * Tiles are used to indicate that the hardware groups sets of pixels and have
+ * each group share certain properties, i.e. color or tile index, or share the
+ * same chroma subsample with only a different intensity. If the engine has no
+ * such grouping, or shares all properties over the entire contents, the value
+ * of this property should be 1. Some tile examples include rescaling, where a
+ * tile width of 2 indicates a pixel doubling in X direction, or in text mode
+ * where a tile width of 8 or 9 corresponds with the width of common bitmap
+ * fonts
+ */
+#define UDI_GFX_PROP_UNIT_WIDTH 5
+/* Constant: UDI_GFX_PROP_UNIT_HEIGHT
+ *
+ * Valid values:
+ *     Any non-zero positive value
+ *
+ * Ranges:
+ *     Any non-empty set of valid values. May be hardwired to 1 for
+ *     framebuffers, or a range of small values for hardware scaling, or any
+ *     larger hardwired number or set for tiling engines.
+ *
+ * See <UDI_GFX_PROP_UNIT_WIDTH>, but for the Y direction. Common values are
+ * 1-2 for framebuffers (doublescanning on or off), identical to the tile
+ * width, or mostly independent.
+ */
+#define UDI_GFX_PROP_UNIT_HEIGHT 6
+#define UDI_GFX_PROP_TRANSLATEX 7
+#define UDI_GFX_PROP_TRANSLATEY 8
+#define UDI_GFX_PROP_SOURCE_WIDTH 12
+#define UDI_GFX_PROP_SOURCE_HEIGHT 13
+#define UDI_GFX_PROP_GL_VERSION 14
+#define UDI_GFX_PROP_GLES_VERSION 15
+#define UDI_GFX_PROP_STATE_BLOCK 16
+/**
+ * Each engine consists of 1 or more operators
+ */
+#define UDI_GFX_PROP_OPERATOR_INDEX 17 //!< Index of operator to inspect/manipulate
+#define UDI_GFX_PROP_OPERATOR_OPCODE 18        //!< Operation performed by operator
+#define UDI_GFX_PROP_OPERATOR_ARG_1 19 //!< argument 1
+#define UDI_GFX_PROP_OPERATOR_ARG_2 20 //!< argument 2
+#define UDI_GFX_PROP_OPERATOR_ARG_3 21 //!< argument 3
+#define UDI_GFX_PROP_COLOR_BITS 22
+#define UDI_GFX_PROP_GL_TARGET 23
+#define UDI_GFX_PROP_INPUTX 25
+#define UDI_GFX_PROP_INPUTY 26
+// properties for removal:
+#define UDI_GFX_PROP_STORE_COUNT 24       // not generic
+#define UDI_GFX_PROP_STORE_WIDTH 9        // not generic
+#define UDI_GFX_PROP_STORE_HEIGHT 10      // not generic
+#define UDI_GFX_PROP_STORE_BITS 11        // not generic
+#define UDI_GFX_PROP_PALETTE 1024         // optional, can be derived from the operator tree
+#define UDI_GFX_PROP_BUFFER 1025          // optional, can be derived from the operator tree
+#define UDI_GFX_PROP_TILESHEET 1026       // optional, can be derived from the operator tree
+// connector properties
+#define UDI_GFX_PROP_SIGNAL 23
+#define UDI_GFX_PROP_CONNECTOR_TYPE 24
+#define UDI_GFX_PROP_VGA_H_FRONT_PORCH 25
+#define UDI_GFX_PROP_VGA_H_BACK_PORCH 26
+#define UDI_GFX_PROP_VGA_H_SYNC 27
+#define UDI_GFX_PROP_VGA_V_FRONT_PORCH 28
+#define UDI_GFX_PROP_VGA_V_BACK_PORCH 29
+#define UDI_GFX_PROP_VGA_V_SYNC 30
+#define UDI_GFX_PROP_DOT_CLOCK 31
+#define UDI_GFX_PROP_VGA_H_SYNC_POL 32
+#define UDI_GFX_PROP_VGA_V_SYNC_POL 33
+/**
+ * Enumeration: UDI_GFX_SIGNAL
+ * Lists the various signal types
+ */
+#define UDI_GFX_SIGNAL_HIDDEN 0
+#define UDI_GFX_SIGNAL_INTEGRATED 0
+#define UDI_GFX_SIGNAL_RGBHV 1
+#define UDI_GFX_SIGNAL_RGBS 2
+#define UDI_GFX_SIGNAL_RGSB 3
+#define UDI_GFX_SIGNAL_YPBPR 4
+#define UDI_GFX_SIGNAL_DVID 5
+#define UDI_GFX_SIGNAL_YUV 6
+#define UDI_GFX_SIGNAL_YIQ 7
+#define UDI_GFX_SIGNAL_Y_UV 8
+#define UDI_GFX_SIGNAL_Y_IQ 9
+#define UDI_GFX_SIGNAL_HDMI 10
+#define UDI_GFX_SIGNAL_TEXT 11
+#define UDI_GFX_SIGNAL_CUSTOM 12
+/**
+ * Enumeration: UDI_GFX_CONNECTOR
+ * Lists the various external connectors
+ */
+#define UDI_GFX_CONNECTOR_HIDDEN 0
+#define UDI_GFX_CONNECTOR_VGA 1
+#define UDI_GFX_CONNECTOR_DVI 2
+#define UDI_GFX_CONNECTOR_SVIDEO 3
+#define UDI_GFX_CONNECTOR_COMPONENT 4
+#define UDI_GFX_CONNECTOR_HDMI 5
+#define UDI_GFX_CONNECTOR_RF 6
+#define UDI_GFX_CONNECTOR_SCART 7
+#define UDI_GFX_CONNECTOR_COMPOSITE 8
+/**
+ * Enumeration: UDI_GFX_OPERATOR
+ * Lists the display output operator
+ * 
+ * a1/a2/a3 represents taking the output of a previous operation
+ * v1/v2/v3 represents the literal value of that argument
+ */
+#define UDI_GFX_OPERATOR_RGB     0 // output = (color) red(a1) + green(a2) + blue(a3) (each component is UDI_GFX_PROP_COLOR_BITS
+#define UDI_GFX_OPERATOR_YUV     1 // output = (color) Y(a1) + U(a2) + V(a3)
+#define UDI_GFX_OPERATOR_YIQ     2 // output = (color) Y(a1) + I(a2) + Q(a3)
+#define UDI_GFX_OPERATOR_I       3 // output = (color) intensity(a1)
+#define UDI_GFX_OPERATOR_ALPHA   4 // output = (color) a1 + alpha(a2)
+#define UDI_GFX_OPERATOR_ADD     5 // output = a1 + a2 + v3
+#define UDI_GFX_OPERATOR_SUB     6 // output = a1 - a2 - v3
+#define UDI_GFX_OPERATOR_MUL     7 // output = a1 * a2
+#define UDI_GFX_OPERATOR_DIV     8 // output = a1 / a2
+#define UDI_GFX_OPERATOR_MAD     9 // output = a1 * a2 + a3
+#define UDI_GFX_OPERATOR_FRC    10 // output = (a1 * a2) / a3
+#define UDI_GFX_OPERATOR_SHR    11 // output = a1 >> (a2 + v3)
+#define UDI_GFX_OPERATOR_SHL    12 // output = a1 << (a2 + v3)
+#define UDI_GFX_OPERATOR_ROR    13 // output = a1 >> a2 (over a3 bits)
+#define UDI_GFX_OPERATOR_ROL    14 // output = a1 << a2 (over a3 bits)
+#define UDI_GFX_OPERATOR_SAR    15 // output = a1 >> a2 (width is a3 bits, i.e. empties are filled with bit a3-1)
+#define UDI_GFX_OPERATOR_SAL    16 // output = a1 <<< (a2 + v3) (empties filled with bit 0)
+#define UDI_GFX_OPERATOR_AND    17 // output = a1 & a2
+#define UDI_GFX_OPERATOR_OR     18 // output = a1 | a2 | v3
+#define UDI_GFX_OPERATOR_NOT    19 // output = ~a1
+#define UDI_GFX_OPERATOR_XOR    20 // output = a1 ^ a2 ^ v3
+#define UDI_GFX_OPERATOR_NEG    21 // output = -a1
+#define UDI_GFX_OPERATOR_SEG    22 // output = (a1 >> v2) & (2**v3-1) (select v3 bits starting from bit v2)
+#define UDI_GFX_OPERATOR_RANGE  23 // output = (a1 > a2) ? a2 : ((a1 < a3) ? a3 : a1)
+#define UDI_GFX_OPERATOR_CONST  24 // output = v1
+#define UDI_GFX_OPERATOR_ATTR   25 // output = property[a1 + v2]
+#define UDI_GFX_OPERATOR_SWITCH 26 // output = output[(a1 % v3) + v2]
+#define UDI_GFX_OPERATOR_BUFFER 27 // output = buffer[a1][a2] (buffer is v3 bits per entry)
+#define UDI_GFX_OPERATOR_X      28 // output = output x pixel
+#define UDI_GFX_OPERATOR_Y      29 // output = output y pixel
+#define UDI_GFX_OPERATOR_TX     30 // output = horizontal tile index belonging to output pixel
+#define UDI_GFX_OPERATOR_TY     31 // output = vertical tile index belonging to output pixel
+#define UDI_GFX_OPERATOR_TXOFF  32 // output = horizontal offset from start of tile
+#define UDI_GFX_OPERATOR_TYOFF  33 // output = vertical offset from start of tile
+#define UDI_GFX_OPERATOR_INPUT  34 // output = input engine[x][y]   component v1
+#define UDI_GFX_OPERATOR_DINPUT 35 // output = input engine[a1][a2] component v3
+// Constant: UDI_GFX_PROVIDER_OPS_NUM
+// the ops number used for the graphics driver
+#define UDI_GFX_PROVIDER_OPS_NUM 1
+// Constant: UDI_GFX_CLIENT_OPS_NUM
+// the ops number used for the graphics application
+#define UDI_GFX_CLIENT_OPS_NUM 2
+// Structure: udi_gfx_bind_cb_t
+// Contains the operations of a driver binding request
+typedef struct {
+    // Variable: gcb
+    // The main control block
+    udi_cb_t gcb;    
+} udi_gfx_bind_cb_t;
+#define UDI_GFX_BIND_CB_NUM 1
+// Function: udi_block_bind_req
+// function pointer prototype for connecting to a block device
+// 
+// in:
+//     cb - A pointer to a <udi_block_bind_cb_t>
+//
+typedef void udi_gfx_bind_req_op_t (udi_gfx_bind_cb_t *cb );
+udi_gfx_bind_req_op_t udi_gfx_bind_req;
+// Function: udi_gfx_bind_ack
+// function pointer prototype for acknowledging a connection request
+// 
+// in:
+//     cb      - A pointer to a <udi_gfx_bind_cb_t>
+//     sockets - The number of addressable socket components
+//     engines - The number of addressable engine components
+//     status  - The result of the bind operation
+//
+typedef void udi_gfx_bind_ack_op_t (udi_gfx_bind_cb_t *cb, udi_index_t sockets, udi_index_t engines, udi_status_t status );
+udi_gfx_bind_ack_op_t udi_gfx_bind_ack;
+// Function: udi_gfx_unbind_req
+// function pointer prototype for disconnecting a block device
+// 
+// in:
+//     cb - A pointer to a <udi_block_bind_cb_t>
+//
+typedef void udi_gfx_unbind_req_op_t (udi_gfx_bind_cb_t *cb );
+udi_gfx_unbind_req_op_t udi_gfx_unbind_req;
+// Function: udi_gfx_unbind_ack
+// function pointer prototype for connecting to a block device
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_bind_cb_t>
+//
+typedef void udi_gfx_unbind_ack_op_t (udi_gfx_bind_cb_t *cb );
+udi_gfx_unbind_ack_op_t udi_gfx_unbind_ack;
+// Structure: udi_gfx_state_cb_t
+// Contains the operations of a read/write transaction
+typedef struct {
+    // Variable: gcb
+    // The main control block
+    udi_cb_t gcb;    
+    udi_ubit32_t subsystem;
+    udi_ubit32_t attribute;
+} udi_gfx_state_cb_t;
+#define UDI_GFX_STATE_CB_NUM 2
+// Function: udi_gfx_set_engine_req
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_set_engine_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+udi_gfx_set_engine_req_op_t udi_gfx_set_engine_req;
+// Function: udi_gfx_set_connector_req
+// function pointer prototype for setting an connector state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_set_connector_req_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+udi_gfx_set_connector_req_op_t udi_gfx_set_connector_req;
+// Function: udi_gfx_set_engine_ack
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_set_engine_ack_op_t (udi_gfx_state_cb_t *cb );
+udi_gfx_set_engine_ack_op_t udi_gfx_set_engine_ack;
+// Function: udi_gfx_set_connector_ack
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_set_connector_ack_op_t (udi_gfx_state_cb_t *cb );
+udi_gfx_set_connector_ack_op_t udi_gfx_set_connector_ack;
+// Function: udi_gfx_get_engine_req
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_get_engine_req_op_t (udi_gfx_state_cb_t *cb );
+udi_gfx_get_engine_req_op_t udi_gfx_get_engine_req;
+// Function: udi_gfx_get_connector_req
+// function pointer prototype for setting an connector state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_get_connector_req_op_t (udi_gfx_state_cb_t *cb );
+udi_gfx_get_connector_req_op_t udi_gfx_get_connector_req;
+// Function: udi_gfx_get_engine_ack
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_get_engine_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+udi_gfx_get_engine_ack_op_t udi_gfx_get_engine_ack;
+// Function: udi_gfx_get_connector_ack
+// function pointer prototype for setting an engine state
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_state_cb_t>
+//
+typedef void udi_gfx_get_connector_ack_op_t (udi_gfx_state_cb_t *cb, udi_ubit32_t value);
+udi_gfx_get_connector_ack_op_t udi_gfx_get_connector_ack;
+// Structure: udi_gfx_range_cb_t
+// Contains the operations of a range request transaction
+typedef struct {
+    // Variable: gcb
+    // The main control block
+    udi_cb_t gcb;    
+    udi_ubit32_t subsystem;
+    udi_ubit32_t attribute;
+    udi_buf_t * rangedata;  
+} udi_gfx_range_cb_t;
+#define UDI_GFX_RANGE_CB_NUM 3
+// Function: udi_gfx_range_engine_req
+// function pointer prototype for getting an engine property range
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_range_cb_t>
+//
+typedef void udi_gfx_range_engine_req_op_t (udi_gfx_range_cb_t *cb );
+udi_gfx_range_engine_req_op_t udi_gfx_range_engine_req;
+// Function: udi_gfx_range_connector_req
+// function pointer prototype for getting a connector property range
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_range_cb_t>
+//
+typedef void udi_gfx_range_connector_req_op_t (udi_gfx_range_cb_t *cb );
+udi_gfx_range_connector_req_op_t udi_gfx_range_connector_req;
+// Function: udi_gfx_range_engine_ack
+// function pointer prototype for replying an engine property range
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_range_cb_t>
+//
+typedef void udi_gfx_range_engine_ack_op_t (udi_gfx_range_cb_t *cb );
+udi_gfx_range_engine_ack_op_t udi_gfx_range_engine_ack;
+// Function: udi_gfx_range_connector_ack
+// function pointer prototype for replying a connector property range
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_range_cb_t>
+//
+typedef void udi_gfx_range_connector_ack_op_t (udi_gfx_range_cb_t *cb );
+udi_gfx_range_connector_ack_op_t udi_gfx_range_connector_ack;
+// Structure: udi_gfx_command_cb_t
+// Contains the operations of a command sequence
+typedef struct {
+    // Variable: gcb
+    // The main control block
+    udi_cb_t gcb;    
+    udi_buf_t * commanddata;
+} udi_gfx_command_cb_t;
+#define UDI_GFX_COMMAND_CB_NUM 4
+// Function: udi_gfx_command
+// function pointer prototype for sending command data
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_command_cb_t>
+//
+typedef void udi_gfx_command_req_op_t (udi_gfx_command_cb_t *cb );
+udi_gfx_command_req_op_t udi_gfx_command_req;
+// Function: udi_gfx_command_ack
+// function pointer prototype for sending command data
+// 
+// in:
+//     cb - A pointer to a <udi_gfx_command_cb_t>
+//
+typedef void udi_gfx_command_ack_op_t (udi_gfx_command_cb_t *cb);
+udi_gfx_command_ack_op_t udi_gfx_command_ack;
+/* Structure: udi_gfx_provider_ops_t
+ The graphics metalanguage e*ntry points (provider side)
+ */
+typedef const struct {
+    udi_channel_event_ind_op_t          *channel_event_ind_op;
+    udi_gfx_bind_req_op_t               *gfx_bind_req_op;
+    udi_gfx_unbind_req_op_t             *gfx_unbind_req_op;
+    udi_gfx_set_connector_req_op_t      *gfx_set_connector_req_op;
+    udi_gfx_set_engine_req_op_t         *gfx_set_engine_req_op;
+    udi_gfx_get_connector_req_op_t      *gfx_get_connector_req_op;
+    udi_gfx_get_engine_req_op_t         *gfx_get_engine_req_op;
+    udi_gfx_range_connector_req_op_t    *gfx_range_connector_req_op;
+    udi_gfx_range_engine_req_op_t       *gfx_range_engine_req_op;
+    udi_gfx_command_req_op_t            *gfx_command_op;
+} udi_gfx_provider_ops_t;
+/* Structure: udi_gfx_client_ops_t
+ * The graphics metalanguage entry points (client side)
+ */
+typedef const struct {
+    udi_channel_event_ind_op_t          *channel_event_ind_op;
+    udi_gfx_bind_ack_op_t               *udi_gfx_bind_ack;
+    udi_gfx_unbind_ack_op_t             *udi_gfx_unbind_ack;
+    udi_gfx_set_connector_ack_op_t      *udi_gfx_set_connector_ack;
+    udi_gfx_set_engine_ack_op_t         *udi_gfx_set_engine_ack;
+    udi_gfx_get_connector_ack_op_t      *udi_gfx_get_connector_ack;
+    udi_gfx_get_engine_ack_op_t         *udi_gfx_get_engine_ack;
+    udi_gfx_range_connector_ack_op_t    *udi_gfx_range_connector_ack;
+    udi_gfx_range_engine_ack_op_t       *udi_gfx_range_engine_ack;
+    udi_gfx_command_ack_op_t            *udi_gfx_command_ack;
+} udi_gfx_client_ops_t;
+// temporary
+#ifndef UDI_ANNOY_ME
+void EngineReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus);
+void ConnectorReturnSimpleRange (int source, int index, int prop, int first, int last, int modulus);
+void EngineReturnConstantRange (int source, int index, int prop, int value);
+void ConnectorReturnConstantRange (int source, int index, int prop, int value);
+void EngineReturnBooleanRange (int source, int index, int prop, int value1, int value2);
+void ConnectorReturnBooleanRange (int source, int index, int prop, int value1, int value2);
+#endif
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Notes.txt b/Usermode/Applications/axwin4_src/Notes.txt
new file mode 100644 (file)
index 0000000..83eff4c
--- /dev/null
@@ -0,0 +1,47 @@
+Layers:
+
+IPC / Client management
+Compositor / Window Manager
+Renderer / Window Contents
+
+Renderers
+Window Management
+> "WM_CreateWindow(Parent, Class, Name)"
+Window Drawing
+> "WD_Fill"
+> "WD_Blit"
+> "WD_LockSurface"
+> "WD_UnlockSurface"
+Decorations
+> ".InitWindow"
+> ".Render"
++ "WM_SetBorder"
+Compositing
+> Dirty rectangling, use 2DCmd to selectively blit
+> Request kernel/server buffers if possible
+
+
+Clients own windows
+Windows are composed of multiple regions that conform to several types (see below)
+- Re-draw is handled by using these regions
+
+Server-side rendering primitives:
+ # Apply to regions, rendered in fixed order, each has an ID
+> Auto-scaling bitmaps
+ - Control backed by an image with three five regions per axis
+  Edge Fixed, Fill, Center Fixed, Fill, Edge Fixed
+ - Definition is via two pixel counts (edge width, fill width), rest is derived
+ - Command to switch backing image to another already provided
+> Tiling bitmaps + filled rects
+> Text (single line)
+> Canvas (Takes drawing commands, draws to internal buffer)
+> Shared buffer (of an unspecified pixel format)
+
+=== Config options ===
+- Root App
+- Display device (- = stdout)
+- Keyboard device (- = stdin)
+- Mouse device
+- Pipe suffix, port number, etc.
+- Key bindings
+
diff --git a/Usermode/Applications/axwin4_src/Server/IWindow.cpp b/Usermode/Applications/axwin4_src/Server/IWindow.cpp
new file mode 100644 (file)
index 0000000..4243e33
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 
+ */
+#include <IWindow.hpp>
+
+namespace AxWin {
+
+
+IWindow::IWindow(const std::string &name):
+       m_name(name)
+{
+}
+
+}      // namespace AxWin
+
diff --git a/Usermode/Applications/axwin4_src/Server/Makefile b/Usermode/Applications/axwin4_src/Server/Makefile
new file mode 100644 (file)
index 0000000..ab82963
--- /dev/null
@@ -0,0 +1,8 @@
+
+include ../../Makefile.cfg
+
+CPPFLAGS += -Iinclude/
+OBJ := IWindow.o
+BIN := AxWinServer
+
+include ../../Makefile.tpl
diff --git a/Usermode/Applications/axwin4_src/Server/compositor.cpp b/Usermode/Applications/axwin4_src/Server/compositor.cpp
new file mode 100644 (file)
index 0000000..db943c5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang)
+ *
+ * compositor.cpp
+ * - Window compositor
+ */
+#include <CVideo.hpp>
+#include <CCompositor.hpp>
+
+namespace AxWin {
+
+CCompositor*   CCompositor::s_instance;
+
+void CCompositor::Initialise(const CConfigCompositor& config)
+{
+       assert(!CCompositor::s_instance);
+       CCompositor::s_instance = new CCompositor(config);
+}
+
+CCompositor::CCompositor(const CConfigCompositor& config):
+       m_config(config)
+{
+       // 
+}
+
+IWindow* CCompositor::CreateWindow(CClient& client)
+{
+       return new CWindow(client);
+}
+
+void CCompositor::Redraw()
+{
+       // Redraw the screen and clear damage rects
+       if( m_damageRects.empty() )
+               return ;
+       
+       // For all windows, check for intersection with damage rect
+}
+
+void CCompositor::DamageArea(const Rect& area)
+{
+
+}
+
+}      // namespace AxWin
+
diff --git a/Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp b/Usermode/Applications/axwin4_src/Server/include/CCompositor.hpp
new file mode 100644 (file)
index 0000000..f6f2e7f
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang) 
+ *
+ * CCompositor.hpp
+ * - Window Compositor
+ */
+#ifndef _CCOMPOSITOR_H_
+#define _CCOMPOSITOR_H_
+
+
+
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Server/include/CConfig.hpp b/Usermode/Applications/axwin4_src/Server/include/CConfig.hpp
new file mode 100644 (file)
index 0000000..aff7fc8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang) 
+ *
+ * CConfig.hpp
+ * - Configuration class
+ */
+#ifndef _CCONFIG_H_
+#define _CCONFIG_H_
+
+#include "CConfigInput.hpp"
+#include "CConfigVideo.hpp"
+#include "CConfigIPC.hpp"
+
+namespace AxWin {
+
+class CConfig
+{
+public:
+       CConfig();
+       
+       bool parseCommandline(int argc, char *argv[]);
+       
+       CConfigInput    m_input;
+       CConfigVideo    m_video;
+       CConfigIPC      m_ipc;
+};
+
+}
+
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Server/include/IRegion.hpp b/Usermode/Applications/axwin4_src/Server/include/IRegion.hpp
new file mode 100644 (file)
index 0000000..8208aa5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang)
+ *
+ * IRegion.hpp
+ * - Representation of a primitive region in a window (part of the window render list)
+ */
+#ifndef _IREGION_HPP_
+#define _IREGION_HPP_
+
+#include <string>
+#include <vector>
+#include "CRect.hpp"
+
+namespace AxWin {
+
+class IRegion
+{
+protected:
+       CWindow&        m_parentWindow;
+public:
+       virtual IRegion(CWindow& parent, const ::AxWin::Rect& position);
+       virtual ~IRegion();
+       
+       virtual void Redraw(const ::AxWin::Rect& area) = 0;
+       virtual bool SetAttr(unsigned int Index, const IPCAttrib& Value) = 0;
+};
+
+};
+
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Server/include/IVideo.hpp b/Usermode/Applications/axwin4_src/Server/include/IVideo.hpp
new file mode 100644 (file)
index 0000000..aa4fc52
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang)
+ *
+ * IVideo.hpp
+ * - Graphics backend abstraction
+ */
+#ifndef _IVIDEO_HPP_
+#define _IVIDEO_HPP_
+
+namespace AxWin {
+
+class IVideo
+{
+public:
+       virtual ~IVideo();
+       
+       // Allocate a new hardware surface
+       IHWSurface&     AllocateHWSurface(uint16_t Width, uint16_t Height);
+       
+       // Request redraw of backbuffer
+       void    Flip();
+};
+
+};
+
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Server/include/IWindow.hpp b/Usermode/Applications/axwin4_src/Server/include/IWindow.hpp
new file mode 100644 (file)
index 0000000..6d91cc1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Acess2 GUI v4
+ * - By John Hodge (thePowersGang)
+ *
+ * IWindow.hpp
+ * - Window abstract base class
+ */
+#ifndef _IWINDOW_HPP_
+#define _IWINDOW_HPP_
+
+#include <string>
+#include <vector>
+#include "CRect.hpp"
+
+namespace AxWin {
+
+class IWindow
+{
+public:
+       virtual IWindow(const ::std::string &name);
+       virtual ~IWindow();
+       
+       virtual void Repaint() = 0;
+       
+       virtual void MouseButton(int ButtonID, int X, int Y, bool Down);
+       virtual void MouseMove(int NewX, int NewY);
+       virtual void KeyEvent(uint32_t Scancode, const ::std::string &Translated, bool Down);
+protected:
+       const ::std::string     m_name;
+};
+
+}      // namespace AxWin
+
+#endif
+
diff --git a/Usermode/Applications/axwin4_src/Server/main.cpp b/Usermode/Applications/axwin4_src/Server/main.cpp
new file mode 100644 (file)
index 0000000..362661a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ */
+#include <CConfig.hpp>
+#include <ipc.hpp>
+#include <input.hpp>
+#include <video.hpp>
+#include <timing.hpp>
+
+using namespace AxWin;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       // - Load configuration (from file and argv)
+       CConfig config;
+       try {
+               config.parseCommandline(argc, argv);
+       }
+       catch(const std::exception& e) {
+               fprintf(stderr, "Exception: %s\n", e.what());
+               return 1;
+       }
+       // - Open graphics
+       Graphics::Initialise(config.m_video);
+       // - Open input
+       Input::Initialise(config.m_input);
+       //  > Handles hotkeys?
+       // - Initialise compositor structures
+       Compositor::Initialise(config.m_compositor);
+       // - Bind IPC channels
+       IPC::Initialise(config.m_ipc);
+       // - Start root child process (from config)
+       // TODO: Spin up child process
+
+       // - Event loop
+       for( ;; )
+       {
+                int    nfd = 0;
+               fd_set  rfds;
+               
+               Input::FillSelect(&nfd, &rfds);
+               IPC::FillSelect(&nfd, &rfds);
+               
+               // TODO: Timer events
+               int64_t timeout = Timing::GetTimeToNextEvent();
+               int rv = ::_SysSelect(nfd, &rfds, NULL, &rfds, NULL, 0);
+               
+               Timing::CheckEvents();
+               
+               Input::HandleSelect(&rfds);
+               IPC::HandleSelect(&rfds);
+               
+               Compositor::Redraw();
+       }
+       return 0;
+}
+
index 0f00bd9..cdf5371 100644 (file)
@@ -186,6 +186,10 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf)
 
        switch( *Buf )
        {
+       case '\a':
+               // Alarm, aka bell
+               //Display_SoundBell(Term);
+               break;
        case '\b':
                // backspace is aprarently just supposed to cursor left (if possible)
                Display_MoveCursor(Term, 0, -1);
@@ -529,6 +533,40 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer)
                                // Reset
                                Display_ResetAttributes(Term);
                        }
+                       else if( args[0] == 48 )
+                       {
+                               // ISO-8613-3 Background
+                               if( args[1] == 2 ) {
+                                       uint32_t        col = 0;
+                                       col |= (uint32_t)args[2] << 16;
+                                       col |= (uint32_t)args[3] << 8;
+                                       col |= (uint32_t)args[4] << 0;
+                                       Display_SetBackground(Term, col);
+                               }
+                               else if( args[1] == 5 ) {
+                                       _SysDebug("TODO: Support xterm palette BG %i", args[2]);
+                               }
+                               else {
+                                       _SysDebug("VT100 Unknown mode set \e[48;%im", args[1]);
+                               }
+                       }
+                       else if( args[0] == 38 )
+                       {
+                               // ISO-8613-3 Foreground
+                               if( args[1] == 2 ) {
+                                       uint32_t        col = 0;
+                                       col |= (uint32_t)args[2] << 16;
+                                       col |= (uint32_t)args[3] << 8;
+                                       col |= (uint32_t)args[4] << 0;
+                                       Display_SetForeground(Term, col);
+                               }
+                               else if( args[1] == 5 ) {
+                                       _SysDebug("TODO: Support xterm palette FG %i", args[2]);
+                               }
+                               else {
+                                       _SysDebug("VT100 Unknown mode set \e[38;%im", args[1]);
+                               }
+                       }
                        else
                        {
                                for( int i = 0; i < argc; i ++ )
@@ -549,6 +587,9 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer)
                                        case 4:
                                                _SysDebug("TODO: \\e[4m - Underscore");
                                                break;
+                                       //case 5:
+                                       //      _SysDebug("TODO: \\e[5m - Blink/bold");
+                                       //      break;
                                        case 7:
                                                _SysDebug("TODO: \\e[7m - Reverse");
                                                break;
@@ -570,6 +611,14 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer)
                                                st->CurBG = 0;
                                                Display_SetBackground( Term, caVT100Colours[ st->CurBG ] );
                                                break;
+                                       case 90 ... 97:
+                                               st->CurFG = args[i]-90 + 8;
+                                               Display_SetForeground( Term, caVT100Colours[ st->CurBG ] );
+                                               break;;
+                                       case 100 ... 107:
+                                               st->CurBG = args[i]-100 + 8;
+                                               Display_SetBackground( Term, caVT100Colours[ st->CurBG ] );
+                                               break;;
                                        default:
                                                _SysDebug("Unknown mode set \\e[%im", args[i]);
                                                break;
index 11833a0..31408e6 100644 (file)
@@ -497,15 +497,13 @@ int SpawnDaemon(tInitProgram *Program)
                char    buffer[101];
                size_t len = snprintf(buffer, 100, "[%lli] init spawning ", _SysTimestamp());
                _SysWrite(out, buffer, len);
-               char ch = '\'';
                for( int i = 0; Program->Command[i]; i ++ )
                {
-                       _SysWrite(out, &ch, 1);
+                       _SysWrite(out, "'", 1);
                        _SysWrite(out, Program->Command[i], strlen(Program->Command[i]));
-                       _SysWrite(out, &ch, 1);
+                       _SysWrite(out, "'", 1);
                }
-               ch = '\n';
-               _SysWrite(out, &ch, 1);
+               _SysWrite(out, "\n", 1);
        }
        
        return SpawnCommand(in, out, err, Program->Command, NULL);
index 9fab060..f22e82f 100644 (file)
@@ -4,7 +4,8 @@
 
 LDFLAGS += -lnet -lreadline
 
-OBJ = main.o
+OBJ = main.o server.o input.o
+OBJ += window.o pseudo_curses.o
 BIN = irc
 
 -include ../Makefile.tpl
diff --git a/Usermode/Applications/irc_src/common.h b/Usermode/Applications/irc_src/common.h
new file mode 100644 (file)
index 0000000..e374328
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include "pseudo_curses.h"
+
+typedef struct sServer tServer;
+
+extern void    _SysDebug(const char *format, ...);
+
+extern int     writef(int FD, const char *Format, ...);
+extern int     OpenTCP(const char *AddressString, short PortNumber);
+extern char    *GetValue(char *Src, int *Ofs);
+
+extern void    Redraw_Screen(void);
+extern void    Exit(const char *Reason) __attribute__((noreturn));
+
+#endif
+
diff --git a/Usermode/Applications/irc_src/input.c b/Usermode/Applications/irc_src/input.c
new file mode 100644 (file)
index 0000000..2236152
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ */
+#include "input.h"
+#include "window.h"
+#include "server.h"
+#include <readline.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+// === PROTOTYPES ===
+void   Input_FillSelect(int *nfds, fd_set *rfds);
+void   Input_HandleSelect(int nfds, const fd_set *rfds);
+ int   ParseUserCommand(char *String);
+
+// === GLOBALS ===
+tReadline      *gpInput_ReadlineInfo;
+
+// === CODE ===
+void Input_FillSelect(int *nfds, fd_set *rfds)
+{
+       if( !gpInput_ReadlineInfo ) {
+               gpInput_ReadlineInfo = Readline_Init(1);
+       }
+       
+       FD_SET(0, rfds);
+       if(*nfds < 0+1)
+               *nfds = 0+1;
+}
+
+void Input_HandleSelect(int nfds, const fd_set *rfds)
+{
+       // User input
+       if(FD_ISSET(0, rfds))
+       {
+               char    *cmd = Readline_NonBlock(gpInput_ReadlineInfo);
+               if( cmd )
+               {
+                       if( cmd[0] )
+                       {
+                               ParseUserCommand(cmd);
+                       }
+                       free(cmd);
+                       // Prompt
+                       SetCursorPos(giTerminal_Height-1, 1);
+                       printf("\x1B[2K");      // Clear line
+                       printf("[%s]", Window_GetName(NULL));
+               }
+       }
+}
+
+void Cmd_join(char *ArgString)
+{
+        int    pos=0;
+       char    *channel_name = GetValue(ArgString, &pos);
+       
+       tServer *srv = Window_GetServer(NULL);
+       
+       if( srv )
+       {
+               Windows_SwitchTo( Window_Create(srv, channel_name) );
+               Redraw_Screen();
+               Server_SendCommand(srv, "JOIN :%s", channel_name);
+       }
+}
+
+void Cmd_quit(char *ArgString)
+{
+       const char *quit_message = ArgString;
+       if( quit_message == NULL || quit_message[0] == '\0' )
+               quit_message = "/quit - Acess2 IRC Client";
+       
+       Servers_CloseAll(quit_message);
+       
+       Exit(NULL);     // NULL = user requested
+}
+
+void Cmd_window(char *ArgString)
+{
+        int    pos = 0;
+       char    *window_id = GetValue(ArgString, &pos);
+        int    window_num = atoi(window_id);
+       
+       if( window_num > 0 )
+       {
+               // Get `window_num`th window
+               tWindow *win = Windows_GetByIndex(window_num-1);
+               if( win )
+               {
+                       Windows_SwitchTo( win );
+               }
+               else
+               {
+                       // Otherwise, silently ignore
+               }
+       }
+       else
+       {
+               window_num = 1;
+               for( tWindow *win; (win = Windows_GetByIndex(window_num-1)); window_num ++ )
+               {
+                       Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, NULL, "%i: %s", window_num, Window_GetName(win));
+               }
+       }
+}
+
+const struct {
+       const char *Name;
+       void    (*Fcn)(char *ArgString);
+} caCommands[] = {
+       {"join", Cmd_join},
+       {"quit", Cmd_quit},
+       {"window", Cmd_window},
+       {"win",    Cmd_window},
+       {"w",      Cmd_window},
+};
+const int ciNumCommands = sizeof(caCommands)/sizeof(caCommands[0]);
+
+/**
+ * \brief Handle a line from the prompt
+ */
+int ParseUserCommand(char *String)
+{
+       if( String[0] == '/' )
+       {
+               char    *command;
+                int    pos = 0;
+               
+               command = GetValue(String, &pos)+1;
+
+               // TODO: Prefix matches
+                int    cmdIdx = -1;
+               for( int i = 0; i < ciNumCommands; i ++ )
+               {
+                       if( strcmp(command, caCommands[i].Name) == 0 ) {
+                               cmdIdx = i;
+                               break;
+                       }
+               }
+               if( cmdIdx != -1 ) {
+                       caCommands[cmdIdx].Fcn(String+pos);
+               }
+               else
+               {
+                       Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, NULL, "Unknown command %s", command);
+               }
+       }
+       else
+       {
+               // Message
+               // - Only send if server is valid and window name is non-empty
+               tServer *srv = Window_GetServer(NULL);
+               if( srv && Window_IsChat(NULL) ) {
+                       Window_AppendMessage(NULL, MSG_CLASS_MESSAGE, Server_GetNick(srv), "%s", String);
+                       Server_SendCommand(srv, "PRIVMSG %s :%s\n", Window_GetName(NULL), String);
+               }
+       }
+       
+       return 0;
+}
diff --git a/Usermode/Applications/irc_src/input.h b/Usermode/Applications/irc_src/input.h
new file mode 100644 (file)
index 0000000..dee859e
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ */
+#ifndef _INPUT_H_
+#define _INPUT_H_
+
+#include <acess/sys.h>
+
+extern void    Input_FillSelect(int *nfds, fd_set *rfds);
+extern void    Input_HandleSelect(int nfds, const fd_set *rfds);
+
+#endif
+
index 1ca53c2..e3e2af4 100755 (executable)
@@ -6,94 +6,41 @@
 #include <stdio.h>
 #include <string.h>
 #include <net.h>
-#include <readline.h>
-#include <acess/devices/pty.h>
 #include <stdarg.h>
 
-// === TYPES ===
-typedef struct sServer {
-       struct sServer  *Next;
-        int    FD;
-       char    InBuf[BUFSIZ+1];
-        int    ReadPos;
-       char    Name[];
-} tServer;
-
-typedef struct sMessage
-{
-       struct sMessage *Next;
-       time_t  Timestamp;
-       tServer *Server;
-        int    Type;
-       char    *Source;        // Pointer into `Data`
-       char    Data[];
-}      tMessage;
+#include "common.h"
+#include "input.h"
+#include "window.h"
+#include "server.h"
 
-typedef struct sWindow
-{
-       struct sWindow  *Next;
-       tMessage        *Messages;
-       tServer *Server;        //!< Canonical server (can be NULL)
-        int    ActivityLevel;
-       char    Name[]; // Channel name / remote user
-}      tWindow;
-
-enum eMessageTypes
-{
-       MSG_TYPE_NULL,
-       MSG_TYPE_SERVER,        // Server message
-       
-       MSG_TYPE_NOTICE,        // NOTICE command
-       MSG_TYPE_JOIN,  // JOIN command
-       MSG_TYPE_PART,  // PART command
-       MSG_TYPE_QUIT,  // QUIT command
-       
-       MSG_TYPE_STANDARD,      // Standard line
-       MSG_TYPE_ACTION,        // /me
-       
-       MSG_TYPE_UNK
-};
+// === TYPES ===
 
 // === PROTOTYPES ===
  int   main(int argc, const char *argv[], const char *envp[]);
  int   MainLoop(void);
  int   ParseArguments(int argc, const char *argv[]);
- int   ParseUserCommand(char *String);
 // --- 
-tServer        *Server_Connect(const char *Name, const char *AddressString, short PortNumber);
-tMessage       *Message_AppendF(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message, ...) __attribute__((format(__printf__,5,6)));
-tMessage       *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message);
-tWindow        *Window_Create(tServer *Server, const char *Name);
 void   Redraw_Screen(void);
-
- int   ProcessIncoming(tServer *Server);
 // --- Helpers
-void   SetCursorPos(int Row, int Col);
+void   Exit(const char *Reason);
  int   writef(int FD, const char *Format, ...);
  int   OpenTCP(const char *AddressString, short PortNumber);
 char   *GetValue(char *Str, int *Ofs);
-static inline int      isdigit(int ch);
 
 // === GLOBALS ===
-char   *gsUsername = "user";
-char   *gsHostname = "acess";
-char   *gsRealName = "Acess2 IRC Client";
-char   *gsNickname = "acess";
-tServer        *gpServers;
-tWindow        gWindow_Status = {
-       NULL, NULL, NULL,       // No next, empty list, no server
-       0, {""} // No activity, empty name (rendered as status)
-};
-tWindow        *gpWindows = &gWindow_Status;
-tWindow        *gpCurrentWindow = &gWindow_Status;
- int   giTerminal_Width = 80;
- int   giTerminal_Height = 25;
+const char     *gsExitReason = "No reason [BUG]";
 
 // ==== CODE ====
 void ExitHandler(void)
 {
        printf("\x1B[?1047l");
-       printf("Quit\n");
+       printf("Quit: %s\n", gsExitReason);
+}
+
+void Exit(const char *Reason)
+{
+       gsExitReason = (Reason ? Reason : "User Requested");
+       exit( (Reason ? 1 : 0) );
 }
 
 int main(int argc, const char *argv[], const char *envp[])
@@ -105,40 +52,31 @@ int main(int argc, const char *argv[], const char *envp[])
        
        atexit(ExitHandler);
        
-       if( _SysIOCtl(1, DRV_IOCTL_TYPE, NULL) != DRV_TYPE_TERMINAL ) {
-               fprintf(stderr, "note: assuming 80x25, can't get terminal dimensions\n");
-               giTerminal_Width = 80;
-               giTerminal_Height = 25;
-       }
-       else {
-               struct ptydims  dims;
-               _SysIOCtl(1, PTY_IOCTL_GETDIMS, &dims);
-               giTerminal_Width = dims.W;
-               giTerminal_Height = dims.H;
-       }
+       ACurses_Init();
        
        printf("\x1B[?1047h");
-       printf("\x1B[%i;%ir", 0, giTerminal_Height-1);
+       printf("\x1B[%i;%ir", 1, giTerminal_Height-1);
        
        SetCursorPos(giTerminal_Height-1, 1);
        printf("[(status)] ");
        
        // HACK: Static server entry
        // UCC (University [of Western Australia] Computer Club) IRC Server
-       gWindow_Status.Server = Server_Connect( "UCC", "130.95.13.18", 6667 );
+       tServer *starting_server = Server_Connect( "UCC", "130.95.13.18", 6667 );
        // Freenode (#osdev)
 //     gWindow_Status.Server = Server_Connect( "Freenode", "89.16.176.16", 6667 );
        // Local servers
 //     gWindow_Status.Server = Server_Connect( "VMHost", "10.0.2.2", 6667 );
 //     gWindow_Status.Server = Server_Connect( "BitlBee", "192.168.1.39", 6667 );
        
-       if( !gWindow_Status.Server )
+       if( !starting_server )
                return -1;
        
-       MainLoop();
+       Windows_SetStatusServer(starting_server);
        
-       for( tServer *srv = gpServers; srv; srv = srv->Next )
-               _SysClose(srv->FD);
+       MainLoop();
+
+       Servers_CloseAll("Client closing");
        
        return 0;
 }
@@ -149,73 +87,25 @@ int MainLoop(void)
        printf("[(status)] ");
        fflush(stdout);
        
-       tReadline *readline_info = Readline_Init(1);
-       
        for( ;; )
        {
                fd_set  readfds, errorfds;
-                int    maxFD = 0;
+                int    nfds = 1;
                
                FD_ZERO(&readfds);
                FD_ZERO(&errorfds);
-               FD_SET(0, &readfds);    // stdin
                
-               fflush(stdout);
+               Input_FillSelect(&nfds, &readfds);
+               Servers_FillSelect(&nfds, &readfds, &errorfds);
                
-               // Fill server FDs in fd_set
-               for( tServer *srv = gpServers; srv; srv = srv->Next )
-               {
-                       FD_SET(srv->FD, &readfds);
-                       FD_SET(srv->FD, &errorfds);
-                       if( srv->FD > maxFD )
-                               maxFD = srv->FD;
-               }
+               int rv = _SysSelect(nfds, &readfds, 0, &errorfds, NULL, 0);
+               if( rv < 0 )    break;
                
-               int rv = _SysSelect(maxFD+1, &readfds, 0, &errorfds, NULL, 0);
-               if( rv == -1 )  break;
-               
-               if(FD_ISSET(0, &readfds))
-               {
-                       // User input
-                       char    *cmd = Readline_NonBlock(readline_info);
-                       if( cmd )
-                       {
-                               if( cmd[0] )
-                               {
-                                       ParseUserCommand(cmd);
-                               }
-                               free(cmd);
-                               // Prompt
-                               SetCursorPos(giTerminal_Height-1, 1);
-                               printf("\x1B[2K");      // Clear line
-                               if( gpCurrentWindow->Name[0] )
-                                       printf("[%s:%s] ",
-                                               gpCurrentWindow->Server->Name, gpCurrentWindow->Name);
-                               else
-                                       printf("[(status)] ");
-                       }
-               }
+               // user input
+               Input_HandleSelect(nfds, &readfds);
                
                // Server response
-               for( tServer *srv = gpServers; srv; srv = srv->Next )
-               {
-                       if(FD_ISSET(srv->FD, &readfds))
-                       {
-                               if( ProcessIncoming(srv) != 0 ) {
-                                       // Oops, error
-                                       _SysDebug("ProcessIncoming failed on FD%i (Server %p %s)",
-                                               srv->FD, srv, srv->Name);
-                                       return 1;
-                               }
-                       }
-                       
-                       if(FD_ISSET(srv->FD, &errorfds))
-                       {
-                               _SysDebug("Error on FD%i (Server %p %s)",
-                                       srv->FD, srv, srv->Name);
-                               return 1;
-                       }
-               }
+               Servers_HandleSelect(nfds, &readfds, &errorfds);
        }
        return 0;
 }
@@ -228,547 +118,12 @@ int ParseArguments(int argc, const char *argv[])
        return 0;
 }
 
-
-void Cmd_join(char *ArgString)
-{
-        int    pos=0;
-       char    *channel_name = GetValue(ArgString, &pos);
-       
-       if( gpCurrentWindow->Server )
-       {
-               gpCurrentWindow = Window_Create(gpCurrentWindow->Server, channel_name);
-               Redraw_Screen();
-               writef(gpCurrentWindow->Server->FD, "JOIN :%s\n", channel_name);
-       }
-}
-
-void Cmd_quit(char *ArgString)
-{
-       const char *quit_message = ArgString;
-       if( quit_message == NULL || quit_message[0] == '\0' )
-               quit_message = "/quit - Acess2 IRC Client";
-       
-       for( tServer *srv = gpServers; srv; srv = srv->Next )
-       {
-               writef(srv->FD, "QUIT :%s\n", quit_message);
-       }
-       
-       exit(0);
-}
-
-void Cmd_window(char *ArgString)
-{
-        int    pos = 0;
-       char    *window_id = GetValue(ArgString, &pos);
-        int    window_num = atoi(window_id);
-       
-       if( window_num > 0 )
-       {
-               tWindow *win;
-               window_num --;  // Move to base 0
-               // Get `window_num`th window
-               for( win = gpWindows; win && window_num--; win = win->Next );
-               if( win ) {
-                       gpCurrentWindow = win;
-                       Redraw_Screen();
-               }
-               // Otherwise, silently ignore
-       }
-       else
-       {
-               window_num = 1;
-               for( tWindow *win = gpWindows; win; win = win->Next, window_num ++ )
-               {
-                       if( win->Name[0] ) {
-                               Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "",
-                                       "%i: %s/%s", window_num, win->Server->Name, win->Name);
-                       }
-                       else {
-                               Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "",
-                                       "%i: (status)", window_num);
-                       }
-               }
-       }
-}
-
-const struct {
-       const char *Name;
-       void    (*Fcn)(char *ArgString);
-} caCommands[] = {
-       {"join", Cmd_join},
-       {"quit", Cmd_quit},
-       {"window", Cmd_window},
-       {"win",    Cmd_window},
-       {"w",      Cmd_window},
-};
-const int ciNumCommands = sizeof(caCommands)/sizeof(caCommands[0]);
-
-/**
- * \brief Handle a line from the prompt
- */
-int ParseUserCommand(char *String)
-{
-       if( String[0] == '/' )
-       {
-               char    *command;
-                int    pos = 0;
-               
-               command = GetValue(String, &pos)+1;
-
-               // TODO: Prefix matches
-                int    cmdIdx = -1;
-               for( int i = 0; i < ciNumCommands; i ++ )
-               {
-                       if( strcmp(command, caCommands[i].Name) == 0 ) {
-                               cmdIdx = i;
-                               break;
-                       }
-               }
-               if( cmdIdx != -1 ) {
-                       caCommands[cmdIdx].Fcn(String+pos);
-               }
-               else
-               {
-                       Message_AppendF(NULL, MSG_TYPE_SERVER, "client", "", "Unknown command %s", command);
-               }
-       }
-       else
-       {
-               // Message
-               // - Only send if server is valid and window name is non-empty
-               if( gpCurrentWindow->Server && gpCurrentWindow->Name[0] )
-               {
-                       Message_Append(gpCurrentWindow->Server, MSG_TYPE_STANDARD,
-                               gsNickname, gpCurrentWindow->Name, String);
-                       writef(gpCurrentWindow->Server->FD,
-                               "PRIVMSG %s :%s\n", gpCurrentWindow->Name,
-                               String
-                               );
-               }
-       }
-       
-       return 0;
-}
-
-/**
- * \brief Connect to a server
- */
-tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber)
-{
-       tServer *ret;
-       
-       ret = calloc(1, sizeof(tServer) + strlen(Name) + 1);
-       
-       strcpy(ret->Name, Name);
-       
-       // Connect to the remove server
-       ret->FD = OpenTCP( AddressString, PortNumber );
-       if( ret->FD == -1 ) {
-               fprintf(stderr, "%s: Unable to create socket\n", Name);
-               return NULL;
-       }
-       
-       // Append to open list
-       ret->Next = gpServers;
-       gpServers = ret;
-       
-       // Read some initial data
-       Message_Append(NULL, MSG_TYPE_SERVER, Name, "", "Connection opened");
-       ProcessIncoming(ret);
-       
-       // Identify
-       writef(ret->FD, "USER %s %s %s : %s\n", gsUsername, gsHostname, AddressString, gsRealName);
-       writef(ret->FD, "NICK %s\n", gsNickname);
-       Message_Append(NULL, MSG_TYPE_SERVER, Name, "", "Identified");
-       //printf("%s: Identified\n", Name);
-       
-       return ret;
-}
-
-tMessage *Message_AppendF(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message, ...)
-{
-       va_list args;
-        int    len;
-       va_start(args, Message);
-       len = vsnprintf(NULL, 0, Message, args);
-       va_end(args);
-       
-       char    buf[len+1];
-       va_start(args, Message);
-       vsnprintf(buf, len+1, Message, args);
-       va_end(args);
-       
-       return Message_Append(Server, Type, Source, Dest, buf);
-}
-
-tMessage *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message)
-{
-       tWindow *win = NULL;
-        int    msgLen = strlen(Message);
-       
-       // Server==NULL indicates an internal message
-       if( Server == NULL || Source[0] == '\0' )
-       {
-               win = &gWindow_Status;
-       }
-       // Determine if it's a channel or PM
-       else if( Dest[0] == '#' || Dest[0] == '&' )     // TODO: Better determining here
-       {
-               for(win = gpWindows; win; win = win->Next)
-               {
-                       if( win->Server == Server && strcmp(win->Name, Dest) == 0 )
-                       {
-                               break;
-                       }
-               }
-               if( !win ) {
-                       //win = Window_Create(Server, Dest);
-                       win = &gWindow_Status;  // Stick it in the status window, just in case
-               }
-       }
-       #if 0
-       else if( strcmp(Dest, Server->Nick) != 0 )
-       {
-               // Umm... message for someone who isn't us?
-               win = &gWindow_Status;  // Stick it in the status window, just in case
-       }
-       #endif
-       // Server message?
-       else if( strchr(Source, '.') )  // TODO: And again, less hack please
-       {
-               #if 1
-               for(win = gpWindows; win; win = win->Next)
-               {
-                       if( win->Server == Server && strcmp(win->Name, Source) == 0 )
-                       {
-                               break;
-                       }
-               }
-               #endif
-               if( !win ) {
-                       win = &gWindow_Status;
-               }
-               
-               // Set source to the server name (instead of the hostname)
-               Source = Server->Name;
-       }
-       // Private message
-       else
-       {
-               for(win = gpWindows; win; win = win->Next)
-               {
-                       if( win->Server == Server && strcmp(win->Name, Source) == 0 )
-                       {
-                               break;
-                       }
-               }
-               if( !win ) {
-                       win = Window_Create(Server, Dest);
-               }
-       }
-
-       // Create message cache 
-       _SysDebug("Win (%s) msg: <%s> %s", win->Name, Source, Message);
-       tMessage        *ret;
-       ret = malloc( sizeof(tMessage) + msgLen + 1 + strlen(Source) + 1 );
-       ret->Source = ret->Data + msgLen + 1;
-       strcpy(ret->Source, Source);
-       strcpy(ret->Data, Message);
-       ret->Type = Type;
-       ret->Server = Server;
-       
-       // Append to window message list
-       ret->Next = win->Messages;
-       win->Messages = ret;
-       
-       // Print now if current window
-       if( win == gpCurrentWindow )
-       {
-               printf("\33[s");
-               printf("\33[T");        // Scroll down 1 (free space below)
-               SetCursorPos(giTerminal_Height-2, 1);
-                int    prefixlen = strlen(Source) + 3;
-                int    avail = giTerminal_Width - prefixlen;
-                int    msglen = strlen(Message);
-               printf("[%s] %.*s", Source, avail, Message);
-               while( msglen > avail ) {
-                       msglen -= avail;
-                       Message += avail;
-                       printf("\33[T");
-                       SetCursorPos(giTerminal_Height-2, prefixlen+1);
-                       printf("%.*s", avail, Message);
-               }
-               printf("\x1b[u");
-       }
-       
-       return ret;
-}
-
-tWindow *Window_Create(tServer *Server, const char *Name)
-{
-       tWindow *ret, *prev = NULL;
-        int    num = 1;
-       
-       // Get the end of the list
-       // TODO: Cache this instead
-       for( ret = gpCurrentWindow; ret; prev = ret, ret = ret->Next )
-               num ++;
-       
-       ret = malloc(sizeof(tWindow) + strlen(Name) + 1);
-       ret->Messages = NULL;
-       ret->Server = Server;
-       ret->ActivityLevel = 1;
-       strcpy(ret->Name, Name);
-       
-       if( prev ) {
-               ret->Next = prev->Next;
-               prev->Next = ret;
-       }
-       else {  // Shouldn't happen really
-               ret->Next = gpWindows;
-               gpWindows = ret;
-       }
-       
-//     printf("Win %i %s:%s created\n", num, Server->Name, Name);
-       
-       return ret;
-}
-
 void Redraw_Screen(void)
 {
-        int    y = 0;
-       tMessage        *msg;
-
        printf("\x1B[2J");      // Clear screen
        printf("\x1B[0;0H");    // Reset cursor
 
-       msg = gpCurrentWindow->Messages;
-       
-       // TODO: Title bar?
-
-       // Note: This renders from the bottom up
-       for( y = giTerminal_Height - 1; y -- && msg; msg = msg->Next)
-       {
-                int    msglen = strlen(msg->Data);
-                int    prefix_len = 3 + strlen(msg->Source);
-                int    line_avail = giTerminal_Width - prefix_len;
-                int    i = 0, done = 0;
-               
-               y -= msglen / line_avail;       // Extra lines (y-- above handles the 1 line case)
-               SetCursorPos(y, 1);
-               printf("[%s] ", msg->Source);
-               
-               while(done < msglen) {
-                       done += printf("%.*s", line_avail, msg->Data+done);
-                       i ++;
-                       SetCursorPos(y+i, prefix_len+1);
-               }
-       }
-
-       // Bottom line is rendered by the prompt
-}
-
-void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message)
-{
-       Message_Append(Server, MSG_TYPE_STANDARD, Dest, Src, Message);
-       //printf("<%s:%s:%s> %s\n", Server->Name, Dest, Src, Message);
-}
-
-void ParseServerLine_Numeric(tServer *Server, const char *ident, int Num, char *Line)
-{
-        int    pos = 0;
-       const char *message;
-       const char *user = GetValue(Line, &pos);
-       
-       if( Line[pos] == ':' ) {
-               message = Line + pos + 1;
-       }
-       else {
-               message = GetValue(Line, &pos);
-       }
-       
-       switch(Num)
-       {
-       case 332:       // Topic
-               user = message; // Channel
-               message = Line + pos + 1;       // Topic
-               Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Topic: %s", message);
-               break;
-       case 333:       // Topic set by
-               user = message; // Channel
-               message = GetValue(Line, &pos); // User
-               GetValue(Line, &pos);   // Timestamp
-               Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Set by %s", message);
-               break;
-       case 353:       // /NAMES list
-               // <user> = <channel> :list
-               // '=' was eaten in and set to message
-               user = GetValue(Line, &pos);    // Actually channel
-               message = Line + pos + 1;       // List
-               Message_AppendF(Server, MSG_TYPE_SERVER, user, user, "Names: %s", message);
-               break;
-       case 366:       // end of /NAMES list
-               // <user> <channel> :msg
-               user = message;
-               message = Line + pos + 1;
-               Message_Append(Server, MSG_TYPE_SERVER, user, user, message);
-               break;
-       case 372:       // MOTD Data
-       case 375:       // MOTD Start
-       case 376:       // MOTD End
-               
-       default:
-               //printf("[%s] %i %s\n", Server->Name, num, message);
-               Message_Append(Server, MSG_TYPE_SERVER, ident, user, message);
-               break;
-       }
-}
-
-void ParseServerLine_String(tServer *Server, const char *ident, const char *cmd, char *Line)
-{
-        int    pos = 0;
-       _SysDebug("ident=%s,cmd=%s,Line=%s", ident, cmd, Line);
-       if( strcmp(cmd, "NOTICE") == 0 )
-       {
-               const char *class = GetValue(Line, &pos);
-               _SysDebug("NOTICE class='%s'", class);
-               
-               const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos);
-               
-               //printf("[%s] NOTICE %s: %s\n", Server->Name, ident, message);
-               char *ident_bang = strchr(ident, '!');
-               if( ident_bang ) {
-                       *ident_bang = '\0';
-               }
-               Message_Append(Server, MSG_TYPE_NOTICE, ident, "", message);
-       }
-       else if( strcmp(cmd, "PRIVMSG") == 0 )
-       {
-               const char *dest = GetValue(Line, &pos);
-               const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos);
-
-               // TODO: Catch when the privmsg is addressed to the user
-
-//             Cmd_PRIVMSG(Server, dest, ident, message);
-               char *ident_bang = strchr(ident, '!');
-               if( ident_bang ) {
-                       *ident_bang = '\0';
-               }
-               Message_Append(Server, MSG_TYPE_STANDARD, ident, dest, message);
-       }
-       else if( strcmp(cmd, "JOIN" ) == 0 )
-       {
-               const char      *channel = Line + pos + 1;
-               
-               Message_AppendF(Server, MSG_TYPE_JOIN, "", channel, "%s has joined", ident);
-               //Window_Create(Server, channel);
-       }
-       else if( strcmp(cmd, "PART" ) == 0 )
-       {
-               const char      *channel = Line + pos + 1;
-               
-               Message_AppendF(Server, MSG_TYPE_PART, "", channel, "%s has left", ident);
-               //Window_Create(Server, channel);
-       }
-       else
-       {
-               Message_AppendF(Server, MSG_TYPE_SERVER, "", "", "Unknown message %s (%s)", cmd, Line);
-       }
-}
-
-/**
- */
-void ParseServerLine(tServer *Server, char *Line)
-{
-        int    pos = 0;
-
-       _SysDebug("[%s] %s", Server->Name, Line);       
-       
-       // Message?
-       if( *Line == ':' )
-       {
-               pos ++;
-               const char *ident = GetValue(Line, &pos);       // Ident (user or server)
-               const char *cmd = GetValue(Line, &pos);
-               
-               // Numeric command
-               if( isdigit(cmd[0]) && isdigit(cmd[1]) && isdigit(cmd[2]) )
-               {
-                        int    num;
-                       num  = (cmd[0] - '0') * 100;
-                       num += (cmd[1] - '0') * 10;
-                       num += (cmd[2] - '0') * 1;
-
-                       ParseServerLine_Numeric(Server, ident, num, Line+pos);
-               }
-               else
-               {
-                       ParseServerLine_String(Server, ident, cmd, Line+pos);
-               }
-       }
-       else {
-               const char *cmd = GetValue(Line, &pos);
-               
-               if( strcmp(cmd, "PING") == 0 ) {
-                       writef(Server->FD, "PONG %s\n", Line+pos);
-               }
-               else {
-                       // Command to client
-                       Message_AppendF(NULL, MSG_TYPE_UNK, "", "", "Client Command: %s", Line);
-               }
-       }
-}
-
-/**
- * \brief Process incoming lines from the server
- */
-int ProcessIncoming(tServer *Server)
-{      
-       char    *ptr, *newline;
-        int    len;
-       
-       // While there is data in the buffer, read it into user memory and 
-       // process it line by line
-       // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer
-       // - Used to avoid blocking
-       #if NON_BLOCK_READ
-       while( (len = _SysIOCtl(Server->FD, 8, NULL)) > 0 )
-       {
-       #endif
-               // Read data
-               len = _SysRead(Server->FD, &Server->InBuf[Server->ReadPos], BUFSIZ - Server->ReadPos);
-               if( len == -1 ) {
-                       return -1;
-               }
-               Server->InBuf[Server->ReadPos + len] = '\0';
-               
-               // Break into lines
-               ptr = Server->InBuf;
-               while( (newline = strchr(ptr, '\n')) )
-               {
-                       *newline = '\0';
-                       if( newline[-1] == '\r' )       newline[-1] = '\0';
-                       ParseServerLine(Server, ptr);
-                       ptr = newline + 1;
-               }
-               
-               // Handle incomplete lines
-               if( ptr - Server->InBuf < len + Server->ReadPos ) {
-                       // Update the read position
-                       // InBuf ReadPos    ptr          ReadPos+len
-                       // | old | new used | new unused |
-                       Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf);
-                       // Copy stuff back (moving "new unused" to the start of the buffer)
-                       memcpy(Server->InBuf, ptr, Server->ReadPos);
-               }
-               else {
-                       Server->ReadPos = 0;
-               }
-       #if NON_BLOCK_READ
-       }
-       #endif
-       
-       return 0;
+       Windows_RepaintCurrent();
 }
 
 /**
@@ -863,12 +218,3 @@ char *GetValue(char *Src, int *Ofs)
        return ret;
 }
 
-void SetCursorPos(int Row, int Col)
-{
-       printf("\x1B[%i;%iH", Row, Col);
-}
-
-static inline int isdigit(int ch)
-{
-       return '0' <= ch && ch < '9';
-}
diff --git a/Usermode/Applications/irc_src/message.h b/Usermode/Applications/irc_src/message.h
new file mode 100644 (file)
index 0000000..0b86f12
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ */
+#ifndef _MESSAGE_H_
+#define _MESSAGE_H_
+
+enum eMessageTypes
+{
+       MSG_TYPE_NULL,
+       MSG_TYPE_SERVER,        // Server message
+       
+       MSG_TYPE_NOTICE,        // NOTICE command
+       MSG_TYPE_JOIN,  // JOIN command
+       MSG_TYPE_PART,  // PART command
+       MSG_TYPE_QUIT,  // QUIT command
+       
+       MSG_TYPE_STANDARD,      // Standard line
+       MSG_TYPE_ACTION,        // /me
+       
+       MSG_TYPE_UNK
+};
+
+enum eMessageClass
+{
+       MSG_CLASS_BARE, // source is unused, just gets timestamped
+       MSG_CLASS_CLIENT,       // source optional, prefixed by '-!-'
+       MSG_CLASS_WALL,         // [SOURCE] MSG         -- Server-provided message
+       MSG_CLASS_MESSAGE,      // <SOURCE> MSG
+       MSG_CLASS_ACTION,       // * SOURCE MSG
+};
+
+typedef struct sMessage        tMessage;
+
+//extern tMessage      *Message_AppendF(tServer *Server, int Type, const char *Src, const char *Dst, const char *Fmt, ...) __attribute__((format(__printf__,5,6)));
+//extern tMessage      *Message_Append(tServer *Server, int Type, const char *Source, const char *Dest, const char *Message);
+
+#endif
+
diff --git a/Usermode/Applications/irc_src/pseudo_curses.c b/Usermode/Applications/irc_src/pseudo_curses.c
new file mode 100644 (file)
index 0000000..bdcb3cf
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ */
+#include "pseudo_curses.h"
+#include <acess/sys.h>
+#include <acess/devices/pty.h>
+#include <stdio.h>
+
+ int   giTerminal_Width = 80;
+ int   giTerminal_Height = 25;
+
+void ACurses_Init(void)
+{
+       if( _SysIOCtl(1, DRV_IOCTL_TYPE, NULL) != DRV_TYPE_TERMINAL ) {
+               _SysDebug("note: assuming 80x25, can't get terminal dimensions");
+               giTerminal_Width = 80;
+               giTerminal_Height = 25;
+       }
+       else {
+               struct ptydims  dims;
+               _SysIOCtl(1, PTY_IOCTL_GETDIMS, &dims);
+               giTerminal_Width = dims.W;
+               giTerminal_Height = dims.H;
+       }
+}
+
+void SetCursorPos(int Row, int Col)
+{
+       printf("\x1B[%i;%iH", Row, Col);
+}
+
diff --git a/Usermode/Applications/irc_src/pseudo_curses.h b/Usermode/Applications/irc_src/pseudo_curses.h
new file mode 100644 (file)
index 0000000..0548e92
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ */
+#ifndef _ACURSES_H_
+#define _ACURSES_H_
+
+extern int     giTerminal_Width;
+extern int     giTerminal_Height;
+
+extern void    ACurses_Init(void);
+extern void    SetCursorPos(int Row, int Col);
+
+#endif
+
diff --git a/Usermode/Applications/irc_src/server.c b/Usermode/Applications/irc_src/server.c
new file mode 100644 (file)
index 0000000..c8bfea5
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "server.h"
+#include "window.h"
+#include <acess/sys.h>
+#include <ctype.h>     // isdigit
+#include <stdio.h>     // vsnprintf
+
+// === PROTOTYPES ===
+tServer        *Server_Connect(const char *Name, const char *AddressString, short PortNumber);
+ int   Server_HandleIncoming(tServer *Server);
+void   ParseServerLine(tServer *Server, char *Line);
+
+// === GLOBALS ===
+const char     *gsUsername = "user";
+const char     *gsHostname = "acess";
+const char     *gsRealName = "Acess2 IRC Client";
+const char     *gsNickname = "acess";
+tServer        *gpServers;
+
+// === CODE ===
+void Servers_FillSelect(int *nfds, fd_set *rfds, fd_set *efds)
+{
+       for( tServer *srv = gpServers; srv; srv = srv->Next )
+       {
+               FD_SET(srv->FD, rfds);
+               FD_SET(srv->FD, efds);
+               if( srv->FD >= *nfds )
+                       *nfds = srv->FD+1;
+       }
+}
+
+void Servers_HandleSelect(int nfds, const fd_set *rfds, const fd_set *efds)
+{
+       for( tServer *srv = gpServers; srv; srv = srv->Next )
+       {
+               if(FD_ISSET(srv->FD, rfds))
+               {
+                        int    rv = Server_HandleIncoming(srv);
+                       if(rv)
+                       {
+                               // Oops, error
+                               _SysDebug("ProcessIncoming failed on FD%i (Server %p %s)",
+                                       srv->FD, srv, srv->Name);
+                               Exit("Processing error");
+                       }
+               }
+               
+               if(FD_ISSET(srv->FD, efds))
+               {
+                       _SysDebug("Error on FD%i (Server %p %s)",
+                               srv->FD, srv, srv->Name);
+                       Exit("Socket error");
+               }
+       }
+}
+
+void Servers_CloseAll(const char *QuitMessage)
+{
+       while( gpServers )
+       {
+               tServer *srv = gpServers;
+               gpServers = srv->Next;
+       
+               Server_SendCommand(srv, "QUIT :%s", QuitMessage);
+               _SysClose(srv->FD);
+               free(srv);
+       }
+}
+
+/**
+ * \brief Connect to a server
+ */
+tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber)
+{
+       tServer *ret;
+       
+       ret = calloc(1, sizeof(tServer) + strlen(Name) + 1);
+       
+       strcpy(ret->Name, Name);
+       
+       // Connect to the remove server
+       ret->FD = OpenTCP( AddressString, PortNumber );
+       if( ret->FD == -1 ) {
+               free(ret);
+               Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Unable to create socket");
+               return NULL;
+       }
+       
+       ret->Nick = strdup(gsNickname);
+       
+       // Append to open list
+       ret->Next = gpServers;
+       gpServers = ret;
+       
+       // Read some initial data
+       Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Unable to create socket");
+       Server_HandleIncoming(ret);
+       
+       // Identify
+       Server_SendCommand(ret, "USER %s %s %s : %s", gsUsername, gsHostname, AddressString, gsRealName);
+       Server_SendCommand(ret, "NICK %s", ret->Nick);
+       Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Name, "Identified");
+       
+       return ret;
+}
+
+const char *Server_GetNick(const tServer *Server)
+{
+       return Server->Nick;
+}
+
+void Server_SendCommand(tServer *Server, const char *Format, ...)
+{
+       va_list args;
+        int    len;
+       
+       va_start(args, Format);
+       len = vsnprintf(NULL, 0, Format, args);
+       va_end(args);
+       
+       char    buf[len+1];
+       va_start(args, Format);
+       vsnprintf(buf, len+1, Format, args);
+       va_end(args);
+       
+       _SysWrite(Server->FD, buf, len);
+       _SysWrite(Server->FD, "\n", 1);
+}
+
+void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message)
+{
+       tWindow *win;
+       if( strcmp(Dest, Server->Nick) == 0 ) {
+               win = Windows_GetByName(Server, Src);
+               if(!win)
+                       win = Window_Create(Server, Src);
+       }
+       else {
+               win = Windows_GetByName(Server, Dest);
+               if(!win)
+                       win = Window_Create(Server, Dest);
+       }
+       Window_AppendMessage(win, MSG_CLASS_MESSAGE, Src, "%s", Message);
+}
+
+/**
+ * \brief Process incoming lines from the server
+ */
+int Server_HandleIncoming(tServer *Server)
+{      
+       char    *ptr, *newline;
+        int    len;
+       
+       // While there is data in the buffer, read it into user memory and 
+       // process it line by line
+       // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer
+       // - Used to avoid blocking
+       #if NON_BLOCK_READ
+       while( (len = _SysIOCtl(Server->FD, 8, NULL)) > 0 )
+       {
+       #endif
+               // Read data
+               len = _SysRead(Server->FD, &Server->InBuf[Server->ReadPos], sizeof(Server->InBuf) - Server->ReadPos);
+               if( len == -1 ) {
+                       return -1;
+               }
+               Server->InBuf[Server->ReadPos + len] = '\0';
+               
+               // Break into lines
+               ptr = Server->InBuf;
+               while( (newline = strchr(ptr, '\n')) )
+               {
+                       *newline = '\0';
+                       if( newline[-1] == '\r' )       newline[-1] = '\0';
+                       ParseServerLine(Server, ptr);
+                       ptr = newline + 1;
+               }
+               
+               // Handle incomplete lines
+               if( ptr - Server->InBuf < len + Server->ReadPos ) {
+                       // Update the read position
+                       // InBuf ReadPos    ptr          ReadPos+len
+                       // | old | new used | new unused |
+                       Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf);
+                       // Copy stuff back (moving "new unused" to the start of the buffer)
+                       memcpy(Server->InBuf, ptr, Server->ReadPos);
+               }
+               else {
+                       Server->ReadPos = 0;
+               }
+       #if NON_BLOCK_READ
+       }
+       #endif
+       
+       return 0;
+}
+
+void ParseServerLine_Numeric(tServer *Server, const char *ident, int Num, char *Line)
+{
+        int    pos = 0;
+       const char *message;
+       const char *user = GetValue(Line, &pos);
+       const char      *timestamp;
+       
+       if( Line[pos] == ':' ) {
+               message = Line + pos + 1;
+       }
+       else {
+               message = GetValue(Line, &pos);
+       }
+       
+       switch(Num)
+       {
+       case 332:       // Topic
+               user = message; // Channel
+               message = Line + pos + 1;       // Topic
+               Window_AppendMsg_Topic( Windows_GetByNameOrCreate(Server, user), message );
+               break;
+       case 333:       // Topic set by
+               user = message; // Channel
+               message = GetValue(Line, &pos); // User
+               timestamp = GetValue(Line, &pos);       // Timestamp
+               Window_AppendMsg_TopicTime( Windows_GetByNameOrCreate(Server, user), message, timestamp );
+               break;
+       case 353:       // /NAMES list
+               // <user> = <channel> :list
+               // '=' was eaten in and set to message
+               user = GetValue(Line, &pos);    // Actually channel
+               message = Line + pos + 1;       // List
+               // TODO: parse and store
+               Window_AppendMessage( Windows_GetByNameOrCreate(Server, user), MSG_CLASS_CLIENT, "NAMES", message );
+               break;
+       case 366:       // end of /NAMES list
+               // <user> <channel> :msg
+               // - Ignored
+               break;
+       case 372:       // MOTD Data
+       case 375:       // MOTD Start
+       case 376:       // MOTD End
+               
+       default:
+               //printf("[%s] %i %s\n", Server->Name, num, message);
+               Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_WALL, Server->Name, "Unknown %i %s", Num, message);
+               break;
+       }
+}
+
+void ParseServerLine_String(tServer *Server, const char *ident, const char *cmd, char *Line)
+{
+        int    pos = 0;
+       _SysDebug("ident=%s,cmd=%s,Line=%s", ident, cmd, Line);
+       if( strcmp(cmd, "NOTICE") == 0 )
+       {
+               const char *class = GetValue(Line, &pos);
+               _SysDebug("NOTICE class='%s'", class);
+               
+               const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos);
+               
+               //printf("[%s] NOTICE %s: %s\n", Server->Name, ident, message);
+               char *ident_bang = strchr(ident, '!');
+               if( ident_bang ) {
+                       *ident_bang = '\0';
+               }
+               // TODO: Colour codes
+               Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_WALL, Server->Name, "%s %s", ident, message);
+       }
+       else if( strcmp(cmd, "PRIVMSG") == 0 )
+       {
+               const char *dest = GetValue(Line, &pos);
+               const char *message = (Line[pos] == ':') ? Line + pos + 1 : GetValue(Line, &pos);
+
+               char *ident_bang = strchr(ident, '!');
+               if( ident_bang ) {
+                       *ident_bang = '\0';
+               }
+               Cmd_PRIVMSG(Server, dest, ident, message);
+       }
+       else if( strcmp(cmd, "JOIN" ) == 0 )
+       {
+               const char      *channel = Line + pos + 1;
+               
+               Window_AppendMsg_Join( Windows_GetByNameOrCreate(Server, channel), ident );
+       }
+       else if( strcmp(cmd, "PART" ) == 0 )
+       {
+               const char      *channel = Line + pos + 1;
+               
+               Window_AppendMsg_Part( Windows_GetByNameOrCreate(Server, channel), ident, "" );
+       }
+       else
+       {
+               Window_AppendMessage( WINDOW_STATUS, MSG_CLASS_BARE, Server->Name, "Unknown command '%s' %s", cmd, Line);
+       }
+}
+
+/**
+ */
+void ParseServerLine(tServer *Server, char *Line)
+{
+        int    pos = 0;
+
+       _SysDebug("[%s] %s", Server->Name, Line);       
+       
+       // Message?
+       if( *Line == ':' )
+       {
+               pos ++;
+               const char *ident = GetValue(Line, &pos);       // Ident (user or server)
+               const char *cmd = GetValue(Line, &pos);
+               
+               // Numeric command
+               if( isdigit(cmd[0]) && isdigit(cmd[1]) && isdigit(cmd[2]) )
+               {
+                        int    num;
+                       num  = (cmd[0] - '0') * 100;
+                       num += (cmd[1] - '0') * 10;
+                       num += (cmd[2] - '0') * 1;
+
+                       ParseServerLine_Numeric(Server, ident, num, Line+pos);
+               }
+               else
+               {
+                       ParseServerLine_String(Server, ident, cmd, Line+pos);
+               }
+       }
+       else {
+               const char *cmd = GetValue(Line, &pos);
+               
+               if( strcmp(cmd, "PING") == 0 ) {
+                       Server_SendCommand(Server, "PONG %s", Line+pos);
+               }
+               else {
+                       // Command to client
+                       Window_AppendMessage(WINDOW_STATUS, MSG_CLASS_CLIENT, Server->Name, "UNK Client Command: %s", Line);
+               }
+       }
+}
diff --git a/Usermode/Applications/irc_src/server.h b/Usermode/Applications/irc_src/server.h
new file mode 100644 (file)
index 0000000..0fd4f51
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ */
+#ifndef _SERVER_H_
+#define _SERVER_H_
+
+#include "common.h"
+
+typedef struct sServer {
+       struct sServer  *Next;
+        int    FD;
+       char    InBuf[1024+1];
+        int    ReadPos;
+       char    *Nick;
+       char    Name[];
+} tServer;
+
+extern void    Servers_FillSelect(int *nfds, fd_set *rfds, fd_set *efds);
+extern void    Servers_HandleSelect(int nfds, const fd_set *rfds, const fd_set *efds);
+extern void    Servers_CloseAll(const char *QuitMessage);
+
+extern tServer *Server_Connect(const char *Name, const char *AddressString, short PortNumber);
+extern  int    Server_HandleIncoming(tServer *Server);
+
+extern const char      *Server_GetNick(const tServer *Server);
+
+extern void    Server_SendCommand(tServer *Server, const char *Format, ...) __attribute__((format(__printf__,2,3)));
+
+#endif
+
diff --git a/Usermode/Applications/irc_src/window.c b/Usermode/Applications/irc_src/window.c
new file mode 100644 (file)
index 0000000..1314cec
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ */
+#include "window.h"
+#include <stddef.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>     // TODO: replace with calls into ACurses_*
+#include <stdlib.h>
+#include <assert.h>
+
+struct sMessage
+{
+       struct sMessage *Next;
+       time_t  Timestamp;
+       enum eMessageClass      Class;
+       char    *Source;        // Pointer to the end of `Data`
+       char    Data[];
+};
+
+struct sWindow
+{
+       struct sWindow  *Next;
+       tMessage        *Messages;
+       tServer *Server;        //!< Canonical server (can be NULL)
+        int    ActivityLevel;
+       char    Name[]; // Channel name / remote user
+};
+
+// === PROTOTYPES ===
+void   Windows_RepaintCurrent(void);
+ int   Windows_int_PaintMessage(tMessage *Message);
+
+// === GLOBALS ===
+tWindow        gWindow_Status = {
+       NULL, NULL, NULL,       // No next, empty list, no server
+       0, {""} // No activity, empty name (rendered as status)
+};
+tWindow        *gpWindows = &gWindow_Status;
+tWindow        *gpCurrentWindow = &gWindow_Status;
+
+// === CODE ===
+void Windows_RepaintCurrent(void)
+{
+       tMessage *msg = gpCurrentWindow->Messages;
+       
+       // TODO: Title bar?
+
+       // Note: This renders from the bottom up
+       for( int y = giTerminal_Height - 1; y -- && msg; msg = msg->Next)
+       {
+               y -= Windows_int_PaintMessage(msg);
+       }
+
+       // Bottom line is rendered by the prompt
+       
+}
+
+int Windows_int_PaintMessage(tMessage *Message)
+{
+       printf("\33[T");        // Scroll down 1 (free space below)
+       SetCursorPos(giTerminal_Height-2, 1);
+       
+       size_t  prefixlen = 0;
+       prefixlen += printf("%02i:%02i:%02i ", (Message->Timestamp/3600)%24, (Message->Timestamp/60)%60, Message->Timestamp%60);
+       switch(Message->Class)
+       {
+       case MSG_CLASS_BARE:    break;
+       case MSG_CLASS_CLIENT:
+               if(Message->Source)
+                       prefixlen += printf("[%s] ", Message->Source);
+               prefixlen += printf("-!- ");
+               break;
+       case MSG_CLASS_WALL:
+               prefixlen += printf("[%s] ", Message->Source);
+               break;
+       case MSG_CLASS_MESSAGE:
+               prefixlen += printf("<%s> ", Message->Source);
+               break;
+       case MSG_CLASS_ACTION:
+               prefixlen += printf("* %s ", Message->Source);
+               break;
+       }
+        int    avail = giTerminal_Width - prefixlen;
+        int    msglen = strlen(Message->Data);
+       
+       int     nLines = 1;
+       printf("%.*s", avail, Message);
+       while( msglen > avail ) {
+               msglen -= avail;
+               Message += avail;
+               printf("\33[T");
+               SetCursorPos(giTerminal_Height-2, prefixlen+1);
+               printf("%.*s", avail, Message);
+               nLines ++;
+       }
+       
+       return nLines;
+}
+
+void Windows_SwitchTo(tWindow *Window)
+{
+       gpCurrentWindow = Window;
+       Redraw_Screen();
+}
+
+void Windows_SetStatusServer(tServer *Server)
+{
+       gWindow_Status.Server = Server;
+}
+
+tWindow *Windows_GetByIndex(int Index)
+{
+       tWindow *win;
+       for( win = gpWindows; win && Index--; win = win->Next )
+               ;
+       return win;
+}
+
+tWindow *Windows_GetByNameEx(tServer *Server, const char *Name, bool CreateAllowed)
+{
+       tWindow *ret, *prev = NULL;
+        int    num = 1;
+       
+       // Get the end of the list and check for duplicates
+       // TODO: Cache this instead
+       for( ret = &gWindow_Status; ret; prev = ret, ret = ret->Next )
+       {
+               if( ret->Server == Server && strcmp(ret->Name, Name) == 0 )
+               {
+                       return ret;
+               }
+               num ++;
+       }
+       if( !CreateAllowed ) {
+               return NULL;
+       }
+       
+       ret = malloc(sizeof(tWindow) + strlen(Name) + 1);
+       ret->Messages = NULL;
+       ret->Server = Server;
+       ret->ActivityLevel = 1;
+       strcpy(ret->Name, Name);
+       
+       if( prev ) {
+               ret->Next = prev->Next;
+               prev->Next = ret;
+       }
+       else {  // Shouldn't happen really
+               ret->Next = gpWindows;
+               gpWindows = ret;
+       }
+       
+//     printf("Win %i %s:%s created\n", num, Server->Name, Name);
+       
+       return ret;
+}
+
+tWindow *Windows_GetByName(tServer *Server, const char *Name)
+{
+       return Windows_GetByNameEx(Server, Name, false);
+}
+
+tWindow *Window_Create(tServer *Server, const char *Name)
+{
+       return Windows_GetByNameEx(Server, Name, true);
+}
+
+
+tWindow *Window_int_ParseSpecial(const tWindow *Window)
+{
+       if( Window == NULL )
+               return gpCurrentWindow;
+       if( Window == WINDOW_STATUS )
+               return &gWindow_Status;
+       return (tWindow*)Window;
+}
+
+const char *Window_GetName(const tWindow *Window) {
+       return Window_int_ParseSpecial(Window)->Name;
+}
+tServer        *Window_GetServer(const tWindow *Window) {
+       return Window_int_ParseSpecial(Window)->Server;
+}
+bool Window_IsChat(const tWindow *Window) {
+       return Window_int_ParseSpecial(Window) != &gWindow_Status;
+}
+
+// -----------------------------
+//  Messages
+// -----------------------------
+void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char *Source, const char *Message, ...)
+{
+       Window = Window_int_ParseSpecial(Window);
+
+       va_list args;
+       
+       va_start(args, Message);
+       size_t len = vsnprintf(NULL, 0, Message, args);
+       va_end(args);
+       
+       tMessage *msg = malloc( sizeof(tMessage) + len+1 + (Source?strlen(Source)+1:0) );
+       assert(msg);
+       
+       msg->Class = Class;
+       msg->Source = (Source ? msg->Data + len+1 : NULL);
+       va_start(args, Message);
+       vsnprintf(msg->Data, len+1, Message, args);
+       va_end(args);
+       
+       msg->Next = Window->Messages;
+       Window->Messages = msg;
+       
+       if( Window == gpCurrentWindow )
+       {
+               // Scroll if needed, and redraw?
+               // - Lazy option of draw at bottom of screen
+               printf("\33[s");        // Save cursor
+               Windows_int_PaintMessage(msg);
+               printf("\x1b[u");       // Restore cursor
+       }
+}
+
+void Window_AppendMsg_Join(tWindow *Window, const char *Usermask)
+{
+       Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined %s", Usermask, Window->Name);
+}
+void Window_AppendMsg_Quit(tWindow *Window, const char *Usermask, const char *Reason)
+{
+       Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined quit (%s)", Usermask, Reason);
+}
+void Window_AppendMsg_Part(tWindow *Window, const char *Usermask, const char *Reason)
+{
+       Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s has joined left %s (%s)", Usermask, Window->Name, Reason);
+}
+void Window_AppendMsg_Topic(tWindow *Window, const char *Topic)
+{
+       Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic of %s is %s", Window->Name, Topic);
+}
+void Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *Timestamp)
+{
+       Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic set by %s at %s", User, Timestamp);
+}
+
diff --git a/Usermode/Applications/irc_src/window.h b/Usermode/Applications/irc_src/window.h
new file mode 100644 (file)
index 0000000..da97f3e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ */
+#ifndef _WINDOW_H_
+#define _WINDOW_H_
+
+#include "common.h"
+#include "message.h"
+#include <stdbool.h>
+
+typedef struct sWindow tWindow;
+extern void    Windows_RepaintCurrent(void);
+
+extern void    Windows_SetStatusServer(tServer *Server);
+extern tWindow *Window_Create(tServer *Server, const char *Name);
+extern tWindow *Windows_GetByIndex(int Index);
+extern tWindow *Windows_GetByName(tServer *Server, const char *Name);
+static inline tWindow  *Windows_GetByNameOrCreate(tServer *Server, const char *Name) {
+       return Window_Create(Server, Name);
+}
+extern void    Windows_SwitchTo(tWindow *Window);
+
+extern void    Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char *Source, const char *Message, ...)
+       __attribute__((format(__printf__,4,5)));
+extern void    Window_AppendMsg_Join(tWindow *Window, const char *Usermask);
+extern void    Window_AppendMsg_Quit(tWindow *Window, const char *Usermask, const char *Reason);
+extern void    Window_AppendMsg_Part(tWindow *Window, const char *Usermask, const char *Reason);
+extern void    Window_AppendMsg_Topic(tWindow *Window, const char *Topic);
+extern void    Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *Timestmap);
+
+extern const char      *Window_GetName(const tWindow *Window);
+extern tServer *Window_GetServer(const tWindow *Window);
+extern bool    Window_IsChat(const tWindow *Window);
+
+#define WINDOW_STATUS  ((void*)-1)
+
+#endif
index a99ff14..79bb845 100644 (file)
@@ -42,8 +42,9 @@ all: _libs $(_BIN) $(_XBIN)
 
 .PHONY: _libs
 
+.PRECIOUS: .no
 
-HEADERS := $(patsubst include_exp/%,../../include/%,$(shell find include_exp/ -name \*.h))
+HEADERS := $(patsubst include_exp/%,../../include/%,$(shell find include_exp/ -name \*.h 2>/dev/null))
 _libs: $(HEADERS)
 
 ../../include/%: include_exp/%
@@ -58,6 +59,7 @@ generate_exp: $(UTESTS:%=EXP_%.txt)
        @echo > /dev/null
 
 utest-build: $(UTESTS:%=TEST_%)
+       @echo > /dev/null
 
 utest-run: $(UTESTS:%=runtest-%)
        @echo > /dev/null
@@ -115,10 +117,12 @@ $(OUTPUTDIR)Libs/%:
 
 obj-native/%.no: %.c
        @mkdir -p $(dir $@)
-       $(NCC) -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF [email protected]
+       $(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF [email protected] '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h
 
 TEST_%: obj-native/TEST_%.no obj-native/%.no
-       $(NCC) -o $@ $^
+       $(NCC) -g -o $@ $^
+
+.SECONDARY: %.no
 
 -include $(UTESTS:%=obj-native/TEST_%.no.dep)
 -include $(UTESTS:%=obj-native/%.no.dep)
index 25a5c56..09a7c8f 100644 (file)
@@ -8,7 +8,7 @@
 
 BIN = $(OUTPUTDIR)Libs/acess.ld
 
-.PHONY: all clean install utest generate_exp
+.PHONY: all clean install utest utest-build utest-run generate_exp
 
 all: $(BIN)
 
@@ -18,7 +18,7 @@ clean:
 install: $(BIN)
 
 # How does one unit test a linker script?
-utest generate_exp:
+utest generate_exp utest-build utest-run:
        @echo > /dev/null
 
 $(BIN):        acess_$(ARCHDIR).ld.h
index 7ddc5f4..3c20896 100644 (file)
@@ -6,7 +6,7 @@
 
 BIN = $(OUTPUTDIR)Libs/crt0.o $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o
 
-.PHONY: all clean install utest generate_exp
+.PHONY: all clean install utest utest-build generate_exp
 
 all: $(BIN)
 
@@ -16,7 +16,7 @@ clean:
        $(RM) $(BIN)
 
 # Disabled unit tests
-utest generate_exp:
+utest generate_exp utest-build utest-run:
        @echo > /dev/null
 
 $(OUTPUTDIR)Libs/%.o: %.c
index 350585a..b80e092 100644 (file)
@@ -56,9 +56,11 @@ _errno:      dw      0       ; Placed in .text, to allow use of relative addressing
 [global %1:func]
 %1:
        push rbx
+       push rbp
        mov eax, %2
        SYSCALL_OP
        mov [DWORD rel _errno], ebx
+       pop rbp
        pop rbx
        ret
 %endmacro
index 6d89224..e065808 100644 (file)
@@ -7,15 +7,71 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>    // strerror
 
-#define TST(t, class, base, val, exp, fmt) do {\
-       t ret = strto##class(#val, NULL, base); \
+#define STR_(v)        #v
+#define STR(v) STR_(v)
+#define TST(t, class, base, val, exp, fmt, ofs, exp_errno) do {\
+       const char *in = val;\
+       char *end;\
+       errno = 0;\
+       t ret = strto##class(in, &end, base); \
        if( ret != exp ) \
-               printf("FAIL strto"#class"('"#val"') != "#val" (act 0x"fmt")\n", ret);\
+               fprintf(stderr, "FAIL strto"#class"('%s') != "#exp" (act "fmt")\n", in, ret);\
+       if( end != in+ofs ) \
+               fprintf(stderr, "FAIL strto"#class"('%s') returned wrong end: %p (+%zi) instead of %p (+%zi)\n",\
+                       in,end,end-in,in+ofs,(size_t)ofs);\
+       if( exp_errno != errno ) \
+               fprintf(stderr, "FAIL strto"#class"('%s') returned wrong errno, exp '%s', got '%s'\n",\
+                       in, strerror(exp_errno), strerror(errno));\
 }while(0)
 
+#define PRIMEBUF(fmt, val)     buf_len = snprintf(buf, sizeof(buf), fmt, val)
+
 int main(int argc, char *argv[])
 {
-       TST(unsigned long, ul, 0, 0x10ec, 0x10ec, "%lx");
-       TST(unsigned long long, ull, 0, 0xffeed10ec, 0xffeed10ec, "%llx");
+       char buf[64];
+       size_t  buf_len;
+       
+       // Success cases
+       TST(unsigned long, ul, 0, "0x10ec", 0x10ec, "%lx", 2+4, 0);
+       TST(unsigned long long, ull, 0, "0xffeed10ec", 0xffeed10ec, "%llx", 2+9, 0);
+       TST(unsigned long long, ull, 0, "01234567", 01234567, "%llo", 8, 0);
+       TST(unsigned long long, ull, 0, "1234567", 1234567, "%lld", 7, 0);
+       TST(long long, ll, 0, "-1", -1, "%lld", 2, 0);  // -1
+       TST(long long, ll, 0, "100113", 100113, "%lld", strlen(in), 0);
+       TST(long long, ll, 0, "0x101", 0x101, "0x%llx", strlen(in), 0);
+       
+       // Invalid strings
+       TST(unsigned long long, ull, 0, "0x",  0, "%llx", 1, 0);        // Single 0
+       TST(unsigned long long, ull, 0, "0xg", 0, "%llx", 1, 0);        // Single 0
+       TST(unsigned long long, ull, 0, "-a", 0, "%llx", 0, 0); // Nothing
+       TST(long long, ll, 0, "-a", 0, "%lld", 0, 0);   // Nothing
+       TST(long long, ll, 0, "-1aaatg", -1, "%lld", 2, 0);     // -1 (with traling junk)
+       TST(long long, ll, 0, "-+1aaatg", 0, "%lld", 0, 0);     // Nothing
+       TST(long long, ll, 0, "-  1", 0, "%lld", 0, 0); // Nothing
+       TST(long long, ll, 0, "01278  1", 0127, "%lld", 4, 0);  // 0127 with junk
+       
+       // Range edges
+       PRIMEBUF("0x%llx", ULLONG_MAX);
+       TST(unsigned long long, ull, 0, buf, ULLONG_MAX, "0x%llx", buf_len, 0);
+       PRIMEBUF("%llu", ULLONG_MAX);
+       TST(unsigned long long, ull, 0, buf, ULLONG_MAX, "%llu", buf_len, 0);
+       PRIMEBUF("-%llu", (long long)LONG_MAX);
+       TST(long, l, 0, buf, -LONG_MAX, "%ld", buf_len, 0);
+       
+       // Out of range
+       // - When the range limit is hit, valid characters should still be consumed (just not used)
+       TST(unsigned long long, ull, 0, "0x10000FFFF0000FFFF", ULLONG_MAX, "%llx", strlen(in), ERANGE);
+       TST(unsigned long, ul, 0, "0x10000FFFF0000FFFF", ULONG_MAX, "%lx", strlen(in), ERANGE);
+       TST(long, l, 0, "0x10000FFFF0000FFFF", LONG_MAX, "%ld", strlen(in), ERANGE);
+       TST(long, l, 0, "-0x10000FFFF0000FFFF", LONG_MIN, "%ld", strlen(in), ERANGE);
+       if( LONG_MIN < -LONG_MAX )
+       {
+               // Ensure that if -LONG_MIN is greater than LONG_MAX, that converting it leaves a range error
+               PRIMEBUF("%ld", LONG_MIN);
+               TST(long, l, 0, buf+1, LONG_MAX, "%ld", buf_len-1, ERANGE);
+       }
 }
index d5a5e97..18a199c 100644 (file)
@@ -22,23 +22,40 @@ int isalnum(int ch) {
        return isalpha(ch) || isdigit(ch);
 }
 
-int toupper(int ch) {
-       if('a'<=ch && ch <='z')
-               return ch - 'a' + 'A';
-       return ch;
+int isxdigit(int ch) {
+       if('0'<=ch&&ch<='9')    return 1;
+       if('a'<=ch&&ch<='f')    return 1;
+       if('F'<=ch&&ch<='F')    return 1;
+       return 0;
 }
-int tolower(int ch) {
-       if('A'<=ch && ch <='Z')
-               return ch - 'A' + 'a';
-       return ch;
+
+int isupper(int ch) {
+       if('A'<=ch && ch <='Z') return 1;
+       return 0;
+}
+
+int islower(int ch) {
+       if('a'<=ch && ch <='z') return 1;
+       return 0;
+}
+
+int ispunct(int ch) {
+       if( isprint(ch) && !isspace(ch) && !isalnum(ch) )
+               return 1;
+       return 0;
 }
 
 int isprint(int ch ) {
-       if( ch < ' ' )  return 0;
-       if( ch > 'z' )  return 0;
+       if( ' ' <= ch && ch <= 'z' )    return 1;
        return 1;
 }
 
+int isgraph(int ch) {
+       // Anything but space
+       if( ' ' < ch && ch <= 'z' )     return 1;
+       return 0;
+}
+
 int isspace(int ch) {
        if(ch == ' ')   return 1;
        if(ch == '\t')  return 1;
@@ -47,12 +64,17 @@ int isspace(int ch) {
        return 0;
 }
 
-int isxdigit(int ch) {
-       if('0'<=ch&&ch<='9')    return 1;
-       if('a'<=ch&&ch<='f')    return 1;
-       if('F'<=ch&&ch<='F')    return 1;
-       return 0;
+int toupper(int ch) {
+       if('a'<=ch && ch <='z')
+               return ch - 'a' + 'A';
+       return ch;
 }
+int tolower(int ch) {
+       if('A'<=ch && ch <='Z')
+               return ch - 'A' + 'a';
+       return ch;
+}
+
 
 // C99
 int isblank(int ch) {
index 6f95457..f5a142a 100644 (file)
@@ -21,13 +21,16 @@ EXPORT char *strerror(int errnum)
        switch((enum libc_eErrorNumbers)errnum)
        {
        case EOK:       return "Success";
+       case ERANGE:    return "Value out of range";
+       case EDOM:      return "Value out of domain";
+       case EILSEQ:    return "Illegal character sequence";
+
        case ENOSYS:    return "Invalid instruction/syscall";
        case EINVAL:    return "Bad argument(s)";
        case EBADF:     return "Invalid file";
        case ENOMEM:    return "No free memory";
        case EACCES:    return "Not permitted";
        case EBUSY:     return "Resource is busy";
-       case ERANGE:    return "Value out of range";
        case ENOTFOUND: return "Item not found";
        case EROFS:     return "Read only filesystem";
        case ENOTIMPL:  return "Not implimented";
@@ -46,8 +49,14 @@ EXPORT char *strerror(int errnum)
        case ENOTTY:    return "Not a TTY";
        case EAGAIN:    return "Try again";
        case EFBIG:     return "File too big";
+       case E2BIG:     return "Value too big";
        case EALREADY:  return "Operation was no-op";
+       case ENOSPC:    return "No space left on the device";
+
        case EAFNOSUPPORT:      return "Address family not supported";
+       case EADDRINUSE:        return "Address already in use";
+       case ETIMEDOUT: return "Operation timed out";
+
        case EINTERNAL: return "Internal error";
        }
        _SysDebug("strerror: errnum=%i unk", errnum);
index d6d9a40..5346032 100644 (file)
@@ -8,6 +8,7 @@
 #include <acess/sys.h>\r
 #include <stdlib.h>\r
 #include <string.h>\r
+#include <assert.h>\r
 #include "lib.h"\r
 \r
 #if 0\r
@@ -308,7 +309,8 @@ EXPORT void *realloc(void *oldPos, size_t bytes)
        \r
        // Check for free space after the block\r
        heap_head *nexthead = NEXT_HEAD(head);\r
-       if( nexthead && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size )\r
+       assert( nexthead <= _heap_end );\r
+       if( nexthead != _heap_end && nexthead->magic == MAGIC_FREE && head->size + nexthead->size >= reqd_size )\r
        {\r
                // Split next block\r
                if( head->size + nexthead->size > reqd_size )\r
@@ -337,12 +339,12 @@ EXPORT void *realloc(void *oldPos, size_t bytes)
        void *ret = _malloc(bytes, __builtin_return_address(0));\r
        if(ret == NULL)\r
                return NULL;\r
+       heap_head *newhead = (heap_head*)ret - 1;\r
        \r
-       //Copy Old Data\r
+       // Copy Old Data\r
+       assert( head->size < newhead->size );\r
        size_t copy_size = head->size-sizeof(heap_head)-sizeof(heap_foot);\r
-       if( copy_size > bytes )\r
-               copy_size = bytes;\r
-       memcpy(ret, oldPos, bytes);\r
+       memcpy(ret, oldPos, copy_size);\r
        free(oldPos);\r
        \r
        //Return\r
index 75e4ce8..69067e8 100644 (file)
@@ -14,21 +14,27 @@ extern "C" {
 
 extern int isalpha(int ch);
 extern int isdigit(int ch);
-
 extern int isalnum(int ch);
+extern int isxdigit(int ch);
 
-extern int toupper(int ch);
-extern int tolower(int ch);
+extern int islower(int ch);
+extern int isupper(int ch);
+extern int ispunct(int ch);
 
 extern int isprint(int ch);
+extern int isgraph(int ch);
 
 extern int isspace(int ch);
 
-extern int isxdigit(int ch);
+extern int iscntrl(int ch);
 
 // C99
 extern int isblank(int ch);
 
+// Conversions
+extern int toupper(int ch);
+extern int tolower(int ch);
+
 #ifdef __cplusplus
 }
 #endif
index f943654..be8c882 100755 (executable)
@@ -1,13 +1,16 @@
 
 enum libc_eErrorNumbers {
        EOK,
+       EDOM,   // (C99) Value out of domain
+       EILSEQ, // (C99) Illegal multi-byte sequence
+       ERANGE, // (C99) Value out of range
+       
        ENOSYS, // Invalid Instruction
        EINVAL, // Invalid Paramater
        EBADF,  // Bad FD
        ENOMEM, // No free memory
        EACCES, // Not permitted
        EBUSY,  // Resource is busy
-       ERANGE, // Value out of range
        ENOTFOUND,      // Item not found
        EROFS,  // Read only
        ENOTIMPL,       // Not implemented
@@ -27,11 +30,15 @@ enum libc_eErrorNumbers {
 
        EAGAIN, // Try again
        EALREADY,       // Operation was a NOP
+       ENOSPC, // (POSIX) No space left on device
        
        EFBIG,  // File too large
+       E2BIG,  // Argument list too large
 
        // psockets
        EAFNOSUPPORT,   
+       EADDRINUSE,     // Specified addres is already in use
+       ETIMEDOUT,
        
        EINTERNAL       // Internal Error
 };
index ed1fce5..b2cb857 100644 (file)
@@ -94,7 +94,7 @@ extern FILE   *open_memstream(char **bufferptr, size_t *lengthptr);
 extern FILE    *fdopen(int fd, const char *modes);
 extern FILE    *tmpfile(void);
 extern int     fclose(FILE *fp);
-extern void    fflush(FILE *fp);
+extern int     fflush(FILE *fp);
 extern off_t   ftell(FILE *fp);
 extern off_t   ftello(FILE *fp);
 extern int     fseek(FILE *fp, long int amt, int whence);
index 7ef1bc7..028ed27 100644 (file)
@@ -29,6 +29,7 @@ extern char   *strrchr(const char *str, int character);
 extern char    *strstr(const char *str1, const char *str2);
 extern size_t  strcspn(const char *haystack, const char *reject);
 extern size_t  strspn(const char *haystack, const char *accept);
+extern char    *strpbrk(const char *haystack, const char *accept);
 
 extern char    *strtok(char *str, const char *delim);
 extern char    *strtok_r(char *str, const char *delim, char **saveptr);
index 1bb90cd..7969f4c 100644 (file)
@@ -374,22 +374,23 @@ int _fflush_int(FILE *fp)
        return ret;\r
 }\r
 \r
-EXPORT void fflush(FILE *fp)\r
+EXPORT int fflush(FILE *fp)\r
 {\r
        if( !fp || fp->FD == FD_NOTOPEN )\r
-               return ;\r
+               return EBADF;\r
        \r
        // Nothing to do for memory files\r
        if( fp->FD == FD_MEMFILE )\r
-               return ;\r
+               return 0;\r
        // Memory streams, update pointers\r
        if( fp->FD == FD_MEMSTREAM ) {\r
                *fp->BufPtr = fp->Buffer;\r
                *fp->LenPtr = fp->BufferPos;\r
-               return ;\r
+               return 0;\r
        }\r
        \r
        _fflush_int(fp);\r
+       return 0;\r
 }\r
 \r
 EXPORT void clearerr(FILE *fp)\r
index aa79ec9..0757c24 100644 (file)
@@ -369,6 +369,19 @@ EXPORT size_t strspn(const char *haystack, const char *accept)
        return ret;
 }
 
+EXPORT char *strpbrk(const char *haystack, const char *accept)
+{
+       while( *haystack )
+       {
+               for( int i = 0; accept[i]; i ++ )
+               {
+                       if( accept[i] == *haystack )
+                               return (char*)haystack;
+               }
+       }
+       return NULL;
+}
+
 char *strtok(char *str, const char *delim)
 {
        static char *__saveptr;
index de7f725..84bf000 100644 (file)
@@ -12,7 +12,7 @@
 
 unsigned long long strtoull(const char *str, char **end, int base)
 {
-       long long       ret = 0;
+       unsigned long long      ret = 0;
        
        if( !str || base < 0 || base > 36 || base == 1 ) {
                if(end)
@@ -27,7 +27,7 @@ unsigned long long strtoull(const char *str, char **end, int base)
        
        // Handle base detection for hex
        if( base == 0 || base == 16 ) {
-               if( *str == '0' && str[1] == 'x' ) {
+               if( *str == '0' && (str[1] == 'x' || str[1] == 'X') && isxdigit(str[2]) ) {
                        str += 2;
                        base = 16;
                }
@@ -43,6 +43,10 @@ unsigned long long strtoull(const char *str, char **end, int base)
        if( base == 0 )
                base = 10;
 
+       // Value before getting within 1 digit of ULLONG_MAX
+       // - Used to avoid overflow in more accurate check
+       unsigned long long      max_before_ullong_max = ULLONG_MAX / base;
+       unsigned int    space_above = ULLONG_MAX - max_before_ullong_max * base;
        while( *str )
        {
                 int    next = -1;
@@ -58,8 +62,31 @@ unsigned long long strtoull(const char *str, char **end, int base)
                        if( 'a' <= *str && *str <= 'a'+base-10-1 )
                                next = *str - 'a' + 10;
                }
+               //_SysDebug("strtoull - ret=0x%llx,next=%i,str='%s'", ret, next, str);
                if( next < 0 )
                        break;
+               
+               // If we're already out of range, keep eating
+               if( ret == ULLONG_MAX ) {
+                       errno = ERANGE;
+                       str ++;
+                       // Keep eating until first unrecognised character
+                       continue;
+               }
+       
+               // Rough then accurate check against max value
+               if( ret >= max_before_ullong_max )
+               {
+                       //_SysDebug("strtoull - 0x%llx>0x%llx", ret, max_before_ullong_max);
+                       if( (ret - max_before_ullong_max) * base + next > space_above ) {
+                               //_SysDebug("strtoull - %u*%u+%u (%u) > %u",
+                               //      (unsigned int)(ret - max_before_ullong_max), base, next, space_above);
+                               ret = ULLONG_MAX;
+                               errno = ERANGE;
+                               str ++;
+                               continue;
+                       }
+               }
                ret *= base;
                ret += next;
                str ++;
@@ -85,7 +112,6 @@ unsigned long strtoul(const char *ptr, char **end, int base)
 long long strtoll(const char *str, char **end, int base)
 {
         int    neg = 0;
-       unsigned long long      ret;
 
        if( !str ) {
                errno = EINVAL;
@@ -96,17 +122,37 @@ long long strtoll(const char *str, char **end, int base)
                str++;
        
        // Check for negative (or positive) sign
-       if(*str == '-' || *str == '+') {
+       if(*str == '-' || *str == '+')
+       {
+               //_SysDebug("strtoll - str[0:1] = '%.2s'", str);
+               if( !isdigit(str[1]) ) {
+                       // Non-digit, invalid string
+                       if(end) *end = (char*)str;
+                       return 0;
+               }
                neg = (*str == '-');
                str++;
        }
 
-       ret = strtoull(str, end, base); 
+       unsigned long long ret = strtoull(str, end, base);      
+       //_SysDebug("strtoll - neg=%i,ret=%llu", neg, ret);
 
-       if( neg )
+       if( neg ) {
+               // Abuses unsigned integer overflow
+               if( ret + LLONG_MIN < ret ) {
+                       errno = ERANGE;
+                       return LLONG_MIN;
+               }
                return -ret;
+       }
        else
+       {
+               if( ret > LLONG_MAX ) {
+                       errno = ERANGE;
+                       return LLONG_MAX;
+               }
                return ret;
+       }
 }
 
 long strtol(const char *str, char **end, int base)
index d6d988f..a860012 100644 (file)
 extern "C" {
 #endif
 
+typedef float  float_t;
+typedef double double_t;
+
+
+#define INFINITY       (*(float*)((uint32_t[]){0x78000000}))
+#define NAN    (*(float*)((uint32_t[]){0x78000001}))
+
 extern double  pow(double x, double y);
 extern double  exp(double x);
 extern double  log(double val);
index dcbf8f5..41684d6 100644 (file)
@@ -11,7 +11,7 @@ LDFLAGS  += -soname libposix.so -Map map.txt -lc
 OBJ  = main.o unistd.o dirent.o stat.o utmpx.o termios.o\r
 OBJ += pwd.o syslog.o sys_time.o sys_ioctl.o sys_resource.o\r
 OBJ += fcntl.o clocks.o sys_wait.o unistd_crypt.o\r
-OBJ += grp.o pty.o mktemp.o utime.o\r
+OBJ += grp.o pty.o mktemp.o utime.o getopt.o\r
 DEPFILES := $(OBJ:%.o=%.d)\r
 BIN = libposix.so\r
 \r
diff --git a/Usermode/Libraries/libposix.so_src/getopt.c b/Usermode/Libraries/libposix.so_src/getopt.c
new file mode 100644 (file)
index 0000000..ab6186b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Acess2 POSIX Emulation Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * getopt.c
+ * - getopt() command line parsing code
+ */
+#include <getopt.h>
+
+// === GLOBALS ===
+char*  optarg;
+ int   opterr;
+ int   optind;
+ int   optopt;
+
+// === CODE ===
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+       return -1;
+}
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/endian.h b/Usermode/Libraries/libposix.so_src/include_exp/endian.h
new file mode 100644 (file)
index 0000000..a70ec0d
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ */
+#ifndef _LIBPOSIX_ENDIAN_H_
+#define _LIBPOSIX_ENDIAN_H_
+
+#define __LITTLE_ENDIAN        0
+#define __BIG_ENDIAN   0
+#define __BYTE_ORDER   __LITTLE_ENDIAN
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/getopt.h b/Usermode/Libraries/libposix.so_src/include_exp/getopt.h
new file mode 100644 (file)
index 0000000..b6db119
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Acess2 POSIX Emulation Layer
+ * - By John Hodge (thePowersGang)
+ *
+ * getopt.h
+ * - getopt() command line parsing code
+ */
+#ifndef _LIBPOSIX_GETOPT_H_
+#define _LIBPOSIX_GETOPT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char*   optarg;
+extern int     opterr;
+extern int     optind;
+extern int     optopt;
+
+extern int     getopt(int argc, char * const argv[], const char *optstring);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/regex.h b/Usermode/Libraries/libposix.so_src/include_exp/regex.h
new file mode 100644 (file)
index 0000000..a830286
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Acess2 POSIX Emulation Library
+ * - By John Hodge (thePowersGang)
+ *
+ * regex.h
+ * - POSIX regular expression support
+ */
+#ifndef _LIBPOSIX_REGEX_H_
+#define _LIBPOSIX_REGEX_H_
+
+typedef struct {
+       void *unused;
+} regex_t;
+
+typedef size_t regoff_t;
+
+typedef struct {
+       regoff_t rm_so;
+       regoff_t rm_eo;
+} regmatch_t;
+
+extern int regcomp(regex_t *preg, const char *regex, int cflags);
+extern int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+extern size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
+extern void regfree(regex_t *preg);
+
+enum {
+       REG_BADBR = 1,
+       REG_BADPAT,
+       REG_BADRPT,
+};
+
+
+#endif
+
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/strings.h b/Usermode/Libraries/libposix.so_src/include_exp/strings.h
new file mode 100644 (file)
index 0000000..9c4114d
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Acess2 POSIX Emulation Library
+ * - By John Hodge (thePowersGang)
+ *
+ * strings.h
+ * - BSD's verison of string.h
+ */
+#ifndef _LIBPOSIX_STRINGS_H_
+#define _LIBPOSIX_STRINGS_H_
+
+
+
+#endif
+
index 6519b3b..10c4779 100644 (file)
@@ -71,6 +71,10 @@ extern int   chmod(const char *path, mode_t mode);
 
 extern int     unlink(const char *pathname);
 
+#define F_OK   00
+#define R_OK   04
+#define W_OK   02
+#define X_OK   01
 extern int     access(const char *pathname, int mode);
 
 extern pid_t   setsid(void);
@@ -93,6 +97,7 @@ extern unsigned int   alarm(unsigned int seconds);
 extern char    *crypt(const char *key, const char *salt);
 
 // - pty.c
+extern int     isatty(int fd);
 extern char    *ttyname(int fd);
 extern int     ttyname_r(int fd, char *buf, size_t buflen);
 
index 3af7bcb..dca2963 100644 (file)
@@ -292,3 +292,21 @@ int ttyname_r(int fd, char *buf, size_t buflen)
 
        return ENOTIMPL;
 }
+
+int isatty(int fd)
+{
+       if( fd < 0 ) {
+               errno = EBADF;
+               return 0;
+       }
+       
+        int    type = _SysIOCtl(fd, DRV_IOCTL_TYPE, NULL);
+       if( type == -1 )
+               return 0;
+       if( type != DRV_TYPE_TERMINAL ) {
+               errno = ENOTTY;
+               // NOTE: Pre POSIX 2001, EINVAL was returned
+               return 0;
+       }
+       return 1;
+}

UCC git Repository :: git.ucc.asn.au