diff --git a/reactos/ChangeLog b/reactos/ChangeLog index a959c89526a..ebaba209db0 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,3 +1,48 @@ +2003-07-11 Casper S. Hornstrup + + * regtests: New directory. + * regtests/kmregtests: Ditto. + * regtests/kmrtint: Ditto. + * regtests/regtests: Ditto. + * regtests/shared: Ditto. + * regtests/win32base: Ditto. + * include/roskrnl.h: New file. + * regtests/Makefile: Ditto. + * regtests/kmregtests/.cvsignore: Ditto. + * regtests/kmregtests/driver.c: Ditto. + * regtests/kmregtests/kmregtests.h: Ditto. + * regtests/kmregtests/Makefile: Ditto. + * regtests/kmrtint/.cvsignore: Ditto. + * regtests/kmrtint/kmrtint.c: Ditto. + * regtests/kmrtint/kmrtint.def: Ditto. + * regtests/kmrtint/kmrtint.edf: Ditto. + * regtests/kmrtint/Makefile: Ditto. + * regtests/regtests/.cvsignore: Ditto. + * regtests/regtests/Makefile: Ditto. + * regtests/regtests/regtests.c: Ditto. + * regtests/shared/.cvsignore: Ditto. + * regtests/shared/Makefile: Ditto. + * regtests/shared/regtests.c: Ditto. + * regtests/shared/regtests.h: Ditto. + * regtests/win32base/.cvsignore: Ditto. + * regtests/win32base/driver.c: Ditto. + * regtests/win32base/file-1.c: Ditto. + * regtests/win32base/Makefile: Ditto. + * regtests/win32base/win32base.def: Ditto. + * regtests/win32base/win32base.edf: Ditto. + * tools/regtests.c: Ditto. + * Makefile: Add target regtests. + * config: Add SEH option. + * rules.mak: Add tool REGTESTS. + * bootdata/hivesys.inf: Add service kmregtests. + * include/win32k/bitmaps.h (DIB_BitmapInfoSize): Correct prototype. + * ntoskrnl/ke/i386/exp.c (KiKernelTrapHandler): Reverse wrong boolean + expression. + * ntoskrnl/ke/i386/usertrap.c (KiUserTrapHandler): Ditto. + * tools/Makefile: Add tool regtests. + * tools/config.mk: Handle SEH option. + * tools/helper.mk: Support regression tests. + 2003-07-11 Casper S. Hornstrup * apps/tests/bitblt/bitblt.c (MainWndProc): Declare variables diff --git a/reactos/Makefile b/reactos/Makefile index 0b11b3c508c..2de48fff44c 100644 --- a/reactos/Makefile +++ b/reactos/Makefile @@ -105,9 +105,12 @@ endif KERNEL_DRIVERS = $(DRIVERS_LIB) $(DEVICE_DRIVERS) $(INPUT_DRIVERS) $(FS_DRIVERS) \ $(NET_DRIVERS) $(NET_DEVICE_DRIVERS) $(STORAGE_DRIVERS) +# Regression tests +REGTESTS = regtests + all: tools dk implib $(LIB_STATIC) $(COMPONENTS) $(HALS) $(BUS) $(LIB_FSLIB) $(DLLS) $(SUBSYS) \ $(LOADERS) $(KERNEL_DRIVERS) $(SYS_APPS) $(SYS_SVC) \ - $(APPS) $(EXT_MODULES) + $(APPS) $(EXT_MODULES) $(REGTESTS) #config: $(TOOLS:%=%_config) @@ -125,7 +128,7 @@ clean: tools dk_clean $(HALS:%=%_clean) \ $(LOADERS:%=%_clean) $(KERNEL_DRIVERS:%=%_clean) $(SUBSYS:%=%_clean) \ $(SYS_APPS:%=%_clean) $(SYS_SVC:%=%_clean) \ $(NET_APPS:%=%_clean) \ - $(APPS:%=%_clean) $(EXT_MODULES:%=%_clean) \ + $(APPS:%=%_clean) $(EXT_MODULES:%=%_clean) $(REGTESTS:%=%_clean) \ clean_after tools_clean clean_after: @@ -136,7 +139,7 @@ install: tools install_dirs install_before \ $(LIB_STATIC:%=%_install) $(LIB_FSLIB:%=%_install) $(DLLS:%=%_install) $(LOADERS:%=%_install) \ $(KERNEL_DRIVERS:%=%_install) $(SUBSYS:%=%_install) \ $(SYS_APPS:%=%_install) $(SYS_SVC:%=%_install) \ - $(APPS:%=%_install) $(EXT_MODULES:%=%_install) + $(APPS:%=%_install) $(EXT_MODULES:%=%_install) $(REGTESTS:%=%_install) dist: $(TOOLS_PATH)/rcopy$(EXE_POSTFIX) dist_clean dist_dirs \ $(HALS:%=%_dist) $(COMPONENTS:%=%_dist) $(BUS:%=%_dist) $(LIB_STATIC:%=%_dist) $(LIB_FSLIB:%=%_dist) \ @@ -742,6 +745,22 @@ $(SUBSYS:%=%_bootcd): %_bootcd: .PHONY: $(SUBSYS) $(SUBSYS:%=%_depends) $(SUBSYS:%=%_implib) $(SUBSYS:%=%_clean) $(SUBSYS:%=%_install) \ $(SUBSYS:%=%_dist) $(SUBSYS:%=%_bootcd) +# +# Regression testsuite +# + +$(REGTESTS): %: + $(MAKE) -C regtests + +$(REGTESTS:%=%_clean): %_clean: + $(MAKE) -C regtests clean + +$(REGTESTS:%=%_install): %_install: + $(MAKE) -C regtests install + +.PHONY: $(REGTESTS) $(REGTESTS:%=%_depends) $(SUBSYS:%=%_clean) $(REGTESTS:%=%_install) + + # # Create an installation # @@ -836,7 +855,6 @@ dist_dirs: .PHONY: dist_clean dist_dirs - etags: find . -name "*.[ch]" -print | etags --language=c - diff --git a/reactos/bootdata/hivesys.inf b/reactos/bootdata/hivesys.inf index 08b68a71b2f..72f1bbde31c 100644 --- a/reactos/bootdata/hivesys.inf +++ b/reactos/bootdata/hivesys.inf @@ -323,6 +323,13 @@ HKLM,"SYSTEM\CurrentControlSet\Services\vmx_svga","Start",0x00010001,0x00000004 HKLM,"SYSTEM\CurrentControlSet\Services\vmx_svga","Type",0x00010001,0x00000001 HKLM,"SYSTEM\CurrentControlSet\Services\vmx_svga\Device0","InstalledDisplayDrivers",0x00010000,"vmx_fb" +; Kernel-mode regression test driver +HKLM,"SYSTEM\CurrentControlSet\Services\kmregtests","ErrorControl",0x00010001,0x00000000 +HKLM,"SYSTEM\CurrentControlSet\Services\kmregtests","Group",0x00000000,"Extended Base" +HKLM,"SYSTEM\CurrentControlSet\Services\kmregtests","ImagePath",0x00020000,"system32\drivers\kmregtests.sys" +HKLM,"SYSTEM\CurrentControlSet\Services\kmregtests","Start",0x00010001,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Services\kmregtests","Type",0x00010001,0x00000001 + ; ControlSet selection settings HKLM,"SYSTEM\Select","Current",0x00010001,0x00000001 diff --git a/reactos/config b/reactos/config index a907ccde0d8..23ab89696e6 100644 --- a/reactos/config +++ b/reactos/config @@ -13,7 +13,7 @@ KDBG := 0 # # Whether to compile for debugging # -DBG := 0 +DBG := 1 # # Whether to compile a multiprocessor or single processor version @@ -25,6 +25,11 @@ MP := 0 # ACPI := 0 +# +# Whether to use Structured Exception Handling +# +SEH := 0 + # # Which version of NDIS do we support up to? diff --git a/reactos/include/roskrnl.h b/reactos/include/roskrnl.h new file mode 100755 index 00000000000..0d3fbb495ab --- /dev/null +++ b/reactos/include/roskrnl.h @@ -0,0 +1,3 @@ +#define NTOS_MODE_KERNEL +#include "ntos.h" +#include "debug.h" diff --git a/reactos/include/win32k/bitmaps.h b/reactos/include/win32k/bitmaps.h index 1d1a5bb4a0c..1ea9ee5a71e 100644 --- a/reactos/include/win32k/bitmaps.h +++ b/reactos/include/win32k/bitmaps.h @@ -45,7 +45,7 @@ INT FASTCALL BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp); HBITMAP FASTCALL BITMAPOBJ_CopyBitmap (HBITMAP hBitmap); INT FASTCALL DIB_GetDIBWidthBytes (INT width, INT depth); int STDCALL DIB_GetDIBImageBytes (INT width, INT height, INT depth); -int FASTCALL DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse); +INT FASTCALL DIB_BitmapInfoSize (const BITMAPINFO * info, WORD coloruse); INT STDCALL BITMAP_GetObject(BITMAPOBJ * bmp, INT count, LPVOID buffer); BOOL FASTCALL Bitmap_InternalDelete( PBITMAPOBJ pBmp ); HBITMAP FASTCALL BitmapToSurf(PBITMAPOBJ BitmapObj); diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index cb3ceda8fd8..241b7e0c198 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -182,8 +182,8 @@ KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2) } Er.ExceptionFlags = ((NTSTATUS) STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode - || (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode ? - 0 : EXCEPTION_NONCONTINUABLE); + || (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode) ? + EXCEPTION_NONCONTINUABLE : 0; KiDispatchException(&Er, 0, Tf, KernelMode, TRUE); diff --git a/reactos/ntoskrnl/ke/i386/usertrap.c b/reactos/ntoskrnl/ke/i386/usertrap.c index 90ba126f098..9253e76b507 100644 --- a/reactos/ntoskrnl/ke/i386/usertrap.c +++ b/reactos/ntoskrnl/ke/i386/usertrap.c @@ -145,8 +145,8 @@ KiUserTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2) Er.ExceptionFlags = ((NTSTATUS) STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode || - (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode ? - 0 : EXCEPTION_NONCONTINUABLE); + (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode) ? + EXCEPTION_NONCONTINUABLE : 0; KiDispatchException(&Er, 0, Tf, UserMode, TRUE); return(0); diff --git a/reactos/regtests/Makefile b/reactos/regtests/Makefile new file mode 100755 index 00000000000..f0ed7bb989c --- /dev/null +++ b/reactos/regtests/Makefile @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +all: + $(MAKE) -C shared all + $(MAKE) -C win32base all + $(MAKE) -C kmregtests all + $(MAKE) -C kmrtint all + $(MAKE) -C regtests all + +clean: + $(MAKE) -C shared clean + $(MAKE) -C win32base clean + $(MAKE) -C kmregtests clean + $(MAKE) -C kmrtint clean + $(MAKE) -C regtests clean + +install: + $(MAKE) -C shared install + $(MAKE) -C win32base install + $(MAKE) -C kmregtests install + $(MAKE) -C kmrtint install + $(MAKE) -C regtests install + +.PHONY: all clean install + diff --git a/reactos/regtests/kmregtests/.cvsignore b/reactos/regtests/kmregtests/.cvsignore new file mode 100755 index 00000000000..d63774a7353 --- /dev/null +++ b/reactos/regtests/kmregtests/.cvsignore @@ -0,0 +1,6 @@ +*.o +*.d +*.exe +*.coff +*.sym +*.map diff --git a/reactos/regtests/kmregtests/Makefile b/reactos/regtests/kmregtests/Makefile new file mode 100755 index 00000000000..8608440f48a --- /dev/null +++ b/reactos/regtests/kmregtests/Makefile @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +PATH_TO_TOP = ../.. + +TARGET_NORC = yes + +TARGET_TYPE = driver + +TARGET_NAME = kmregtests + +TARGET_LIBS = $(SDK_PATH_LIB)/rtshared.a + +TARGET_CFLAGS = -I../shared + +TARGET_GENREGTESTS = yes + +TARGET_OBJECTS = \ + _regtests.o \ + driver.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/reactos/regtests/kmregtests/driver.c b/reactos/regtests/kmregtests/driver.c new file mode 100755 index 00000000000..07c515416dc --- /dev/null +++ b/reactos/regtests/kmregtests/driver.c @@ -0,0 +1,182 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/kmregtests/driver.c + * PURPOSE: Kernel-mode regression testing driver + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#define NTOS_MODE_KERNEL +#include +#include "regtests.h" +#include "kmregtests.h" + +#define NDEBUG +#include + +PVOID +AllocateMemory(ULONG Size) +{ + return ExAllocatePool(NonPagedPool, Size); +} + + +VOID +FreeMemory(PVOID Base) +{ + ExFreePool(NonPagedPool); +} + +VOID +ShutdownBochs() +{ + /* Shutdown bochs programmatically */ + WRITE_PORT_BUFFER_UCHAR((PUCHAR) 0x8900, + (PUCHAR) "Shutdown", + strlen("Shutdown")); +} + +NTSTATUS +STDCALL +KMRegTestsRun( + PIRP Irp, + PIO_STACK_LOCATION IrpSp) +{ + InitializeTests(); + RegisterTests(); + PerformTests(); + ShutdownBochs(); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + return STATUS_SUCCESS; +} + +NTSTATUS +STDCALL +KMRegTestsDispatch( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: IOCTL dispatch routine + * ARGUMENTS: + * DeviceObject = Pointer to a device object for this driver + * Irp = Pointer to a I/O request packet + * RETURNS: + * Status of the operation + */ +{ + NTSTATUS Status; + PIO_STACK_LOCATION IrpSp; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + DPRINT("Called. DeviceObject is at (0x%X), IRP is at (0x%X), IrpSp->FileObject (0x%X).\n", + DeviceObject, Irp, IrpSp->FileObject); + + Irp->IoStatus.Information = 0; + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + case IOCTL_KMREGTESTS_RUN: + Status = KMRegTestsRun(Irp, IrpSp); + break; + + default: + DPRINT("Unknown IOCTL (0x%X).\n", + IrpSp->Parameters.DeviceIoControl.IoControlCode); + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (Status != STATUS_PENDING) { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + DPRINT("Leaving. Status (0x%X).\n", Status); + + return Status; +} + +NTSTATUS STDCALL +KMRegTestsOpenClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) +{ + PIO_STACK_LOCATION piosStack = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS nErrCode; + + nErrCode = STATUS_SUCCESS; + + switch(piosStack->MajorFunction) + { + /* Opening and closing handles to the device */ + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + break; + + /* Write data */ + case IRP_MJ_WRITE: + /* Ignore */ + Irp->IoStatus.Information = 0; + break; + + /* Read data */ + case IRP_MJ_READ: + /* Ignore */ + Irp->IoStatus.Information = 0; + nErrCode = STATUS_END_OF_FILE; + break; + + /* Unsupported operations */ + default: + nErrCode = STATUS_NOT_IMPLEMENTED; + } + + Irp->IoStatus.Status = nErrCode; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return nErrCode; +} + +NTSTATUS STDCALL +KMRegTestsUnload(PDRIVER_OBJECT DriverObject) +{ + return STATUS_SUCCESS; +} + +NTSTATUS STDCALL +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + PDEVICE_OBJECT DeviceObject; + UNICODE_STRING DeviceName; + UNICODE_STRING DosName; + NTSTATUS Status; + + /* Register driver routines */ + DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH) KMRegTestsOpenClose; + DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH) KMRegTestsOpenClose; + DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH) KMRegTestsOpenClose; + DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH) KMRegTestsOpenClose; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH) KMRegTestsDispatch; + DriverObject->DriverUnload = (PDRIVER_UNLOAD) KMRegTestsUnload; + + /* Create device */ + RtlInitUnicodeString(&DeviceName, + L"\\Device\\KMRegTests"); + + Status = IoCreateDevice(DriverObject, + 0, + &DeviceName, + FILE_DEVICE_NULL, + 0, + FALSE, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + DeviceObject->Flags |= DO_BUFFERED_IO; + + return Status; +} diff --git a/reactos/regtests/kmregtests/kmregtests.h b/reactos/regtests/kmregtests/kmregtests.h new file mode 100755 index 00000000000..ab24c408a57 --- /dev/null +++ b/reactos/regtests/kmregtests/kmregtests.h @@ -0,0 +1,19 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/kmregtests/kmregtests.h + * PURPOSE: Kernel-mode component regression testing + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#include + +/* KMREGTESTS IOCTL code definitions */ + +#define FSCTL_KMREGTESTS_BASE FILE_DEVICE_NAMED_PIPE // ??? + +#define KMREGTESTS_CTL_CODE(Function, Method, Access) \ + CTL_CODE(FSCTL_KMREGTESTS_BASE, Function, Method, Access) + +#define IOCTL_KMREGTESTS_RUN \ + KMREGTESTS_CTL_CODE(0, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/reactos/regtests/kmrtint/.cvsignore b/reactos/regtests/kmrtint/.cvsignore new file mode 100755 index 00000000000..611644d8c77 --- /dev/null +++ b/reactos/regtests/kmrtint/.cvsignore @@ -0,0 +1,6 @@ +*.o +*.d +*.dll +*.coff +*.sym +*.map diff --git a/reactos/regtests/kmrtint/Makefile b/reactos/regtests/kmrtint/Makefile new file mode 100755 index 00000000000..9664a53c08c --- /dev/null +++ b/reactos/regtests/kmrtint/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +PATH_TO_TOP = ../.. + +TARGET_NORC = yes + +TARGET_TYPE = dynlink + +TARGET_NAME = kmrtint + +TARGET_SDKLIBS = ntdll.a kernel32.a + +TARGET_CFLAGS = -I../shared -I../kmregtests + +TARGET_BASE = 0x50000000 + +TARGET_OBJECTS = \ + kmrtint.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/reactos/regtests/kmrtint/kmrtint.c b/reactos/regtests/kmrtint/kmrtint.c new file mode 100755 index 00000000000..a336c8c8ac1 --- /dev/null +++ b/reactos/regtests/kmrtint/kmrtint.c @@ -0,0 +1,86 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/kmrtint/kmrtint.c + * PURPOSE: Kernel-mode regression testing driver user-mode interface + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#define NTOS_MODE_USER +#include +#include "regtests.h" +#include "kmregtests.h" + +#define NDEBUG +#include + +HANDLE +OpenDevice() +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DeviceName; + IO_STATUS_BLOCK Iosb; + HANDLE DeviceHandle; + NTSTATUS Status; + + RtlInitUnicodeString(&DeviceName, + L"\\Device\\KMRegTests"); + InitializeObjectAttributes( + &ObjectAttributes, + &DeviceName, + 0, + NULL, + NULL); + + Status = NtCreateFile( + &DeviceHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &ObjectAttributes, + &Iosb, + NULL, + 0, + 0, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + if (!NT_SUCCESS(Status)) + { + return INVALID_HANDLE_VALUE; + } + return DeviceHandle; +} + +VOID STDCALL +RegTestMain() +{ + IO_STATUS_BLOCK Iosb; + HANDLE DeviceHandle; + NTSTATUS Status; + + DeviceHandle = OpenDevice(); + if (DeviceHandle != INVALID_HANDLE_VALUE) + { + Status = NtDeviceIoControlFile( + DeviceHandle, + NULL, + NULL, + NULL, + &Iosb, + IOCTL_KMREGTESTS_RUN, + NULL, + 0, + NULL, + 0); + if (Status == STATUS_PENDING) { + Status = NtWaitForSingleObject(DeviceHandle, FALSE, NULL); + } + + NtClose(DeviceHandle); + } + else + { + DPRINT("Cannot open KMRegTests device.\n"); + } +} diff --git a/reactos/regtests/kmrtint/kmrtint.def b/reactos/regtests/kmrtint/kmrtint.def new file mode 100755 index 00000000000..4f915f52c53 --- /dev/null +++ b/reactos/regtests/kmrtint/kmrtint.def @@ -0,0 +1,3 @@ +LIBRARY kmrtint.dll +EXPORTS +RegTestMain@0 diff --git a/reactos/regtests/kmrtint/kmrtint.edf b/reactos/regtests/kmrtint/kmrtint.edf new file mode 100755 index 00000000000..031c73fecb9 --- /dev/null +++ b/reactos/regtests/kmrtint/kmrtint.edf @@ -0,0 +1,3 @@ +LIBRARY kmrtint.dll +EXPORTS +RegTestMain=RegTestMain@0 diff --git a/reactos/regtests/regtests/.cvsignore b/reactos/regtests/regtests/.cvsignore new file mode 100755 index 00000000000..d63774a7353 --- /dev/null +++ b/reactos/regtests/regtests/.cvsignore @@ -0,0 +1,6 @@ +*.o +*.d +*.exe +*.coff +*.sym +*.map diff --git a/reactos/regtests/regtests/Makefile b/reactos/regtests/regtests/Makefile new file mode 100755 index 00000000000..4726beebf88 --- /dev/null +++ b/reactos/regtests/regtests/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +PATH_TO_TOP = ../.. + +TARGET_NORC = yes + +TARGET_TYPE = program + +TARGET_APPTYPE = console + +TARGET_NAME = regtests + +TARGET_SDKLIBS = rtshared.a ntdll.a kernel32.a + +TARGET_CFLAGS = -I../shared + +TARGET_OBJECTS = \ + regtests.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk + +# EOF diff --git a/reactos/regtests/regtests/regtests.c b/reactos/regtests/regtests/regtests.c new file mode 100755 index 00000000000..5380d20a661 --- /dev/null +++ b/reactos/regtests/regtests/regtests.c @@ -0,0 +1,37 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/regtests/regtests.c + * PURPOSE: Regression testing host + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#define NTOS_MODE_USER +#include +#include "regtests.h" + +VOID +RunTestDriver(LPTSTR FileName) +{ + TestDriverMain Main; + HMODULE hModule; + + hModule = LoadLibrary(FileName); + if (hModule != NULL) + { + Main = (TestDriverMain) GetProcAddress(hModule, "RegTestMain"); + if (Main != NULL) + { + (Main)(); + } + FreeLibrary(hModule); + } +} + +int +main(int argc, char* argv[]) +{ + RunTestDriver("win32base.dll"); + RunTestDriver("kmrtint.dll"); + return 0; +} diff --git a/reactos/regtests/shared/.cvsignore b/reactos/regtests/shared/.cvsignore new file mode 100755 index 00000000000..9750878a108 --- /dev/null +++ b/reactos/regtests/shared/.cvsignore @@ -0,0 +1,5 @@ +*.o +*.d +*.a +*.sym +*.map diff --git a/reactos/regtests/shared/Makefile b/reactos/regtests/shared/Makefile new file mode 100755 index 00000000000..85e958f0a89 --- /dev/null +++ b/reactos/regtests/shared/Makefile @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +PATH_TO_TOP = ../.. + +TARGET_NORC = yes + +TARGET_TYPE = library + +TARGET_NAME = rtshared + +TARGET_OBJECTS = \ + regtests.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/regtests/shared/regtests.c b/reactos/regtests/shared/regtests.c new file mode 100755 index 00000000000..48959422ec6 --- /dev/null +++ b/reactos/regtests/shared/regtests.c @@ -0,0 +1,109 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/shared/regtests.c + * PURPOSE: Regression testing framework + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#include +#define NTOS_MODE_USER +#include +#include "regtests.h" + +#define NDEBUG +#include + +LIST_ENTRY AllTests; + +int +DriverTest() +{ + /* Dummy */ + return 0; +} + + +int +_regtestsTest() +{ + /* Dummy */ + return 0; +} + + +VOID +InitializeTests() +{ + InitializeListHead(&AllTests); +} + +VOID +PerformTest(PROS_TEST Test) +{ + char TestName[200]; + char Buffer[200]; + int Result; + + memset(TestName, 0, sizeof(TestName)); + memset(Buffer, 0, sizeof(Buffer)); + + if (!((Test->Routine)(TESTCMD_TESTNAME, TestName) == 0)) + { + strcpy(TestName, "Unnamed"); + } + +#ifdef SEH + __try { +#endif + Result = (Test->Routine)(TESTCMD_RUN, Buffer); +#ifdef SEH + } __except(EXCEPTION_EXECUTE_HANDLER) { + Result = TS_FAILED; + strcpy(Buffer, "Failed due to exception"); + } +#endif + + if (Result != TS_OK) + { + DbgPrint("ROSREGTEST: (%s) Status: Failed (%s)\n", TestName, Buffer); + } + else + { + DbgPrint("ROSREGTEST: (%s) Status: Success\n", TestName); + } +} + +VOID +PerformTests() +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PROS_TEST Current; + + CurrentEntry = AllTests.Flink; + while (CurrentEntry != &AllTests) + { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, ROS_TEST, ListEntry); + PerformTest(Current); + CurrentEntry = NextEntry; + } +} + +VOID +AddTest(TestRoutine Routine) +{ + PROS_TEST Test; + + Test = (PROS_TEST) AllocateMemory(sizeof(ROS_TEST)); + if (Test == NULL) + { + DbgPrint("Out of memory"); + return; + } + + Test->Routine = Routine; + + InsertTailList(&AllTests, &Test->ListEntry); +} diff --git a/reactos/regtests/shared/regtests.h b/reactos/regtests/shared/regtests.h new file mode 100755 index 00000000000..4d75575b92c --- /dev/null +++ b/reactos/regtests/shared/regtests.h @@ -0,0 +1,44 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/shared/regtests.h + * PURPOSE: Regression testing + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#include + +/* Valid values for Command parameter of TestRoutine */ +#define TESTCMD_RUN 0 /* Buffer contains information about what failed */ +#define TESTCMD_TESTNAME 1 /* Buffer contains description of test */ + +/* Valid values for return values of TestRoutine */ +#define TS_EXCEPTION -1 +#define TS_OK 0 +#define TS_FAILED 1 + +/* + * Test routine prototype + * Command - The command to process + * Buffer - Pointer to buffer in which to return context information + */ +typedef int (*TestRoutine)(int Command, char *Buffer); + +/* Test driver entry routine */ +typedef VOID STDCALL (*TestDriverMain)(); + +typedef struct _ROS_TEST +{ + LIST_ENTRY ListEntry; + TestRoutine Routine; +} ROS_TEST, *PROS_TEST; + +extern LIST_ENTRY AllTests; + +extern VOID InitializeTests(); +extern VOID RegisterTests(); +extern VOID PerformTests(); + +/* Routines provided by the driver */ +extern PVOID AllocateMemory(ULONG Size); +extern VOID FreeMemory(PVOID Base); diff --git a/reactos/regtests/win32base/.cvsignore b/reactos/regtests/win32base/.cvsignore new file mode 100755 index 00000000000..611644d8c77 --- /dev/null +++ b/reactos/regtests/win32base/.cvsignore @@ -0,0 +1,6 @@ +*.o +*.d +*.dll +*.coff +*.sym +*.map diff --git a/reactos/regtests/win32base/Makefile b/reactos/regtests/win32base/Makefile new file mode 100755 index 00000000000..28b12245c0b --- /dev/null +++ b/reactos/regtests/win32base/Makefile @@ -0,0 +1,26 @@ +# $Id: Makefile,v 1.1 2003/07/11 18:13:57 chorns Exp $ + +PATH_TO_TOP = ../.. + +TARGET_NORC = yes + +TARGET_TYPE = dynlink + +TARGET_NAME = win32base + +TARGET_SDKLIBS = rtshared.a ntdll.a kernel32.a + +TARGET_CFLAGS = -I../shared + +TARGET_BASE = 0x60000000 + +TARGET_GENREGTESTS = yes + +TARGET_OBJECTS = \ + _regtests.o \ + driver.o \ + file-1.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk diff --git a/reactos/regtests/win32base/driver.c b/reactos/regtests/win32base/driver.c new file mode 100755 index 00000000000..3c89a692cb0 --- /dev/null +++ b/reactos/regtests/win32base/driver.c @@ -0,0 +1,33 @@ +/* + * PROJECT: ReactOS kernel + * FILE: regtests/win32base/driver.c + * PURPOSE: Win32 base services regression testing driver + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * 06-07-2003 CSH Created + */ +#define NTOS_MODE_USER +#include +#include "regtests.h" + +PVOID +AllocateMemory(ULONG Size) +{ + return (PVOID) RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); +} + + +VOID +FreeMemory(PVOID Base) +{ + RtlFreeHeap(RtlGetProcessHeap(), 0, Base); +} + + +VOID STDCALL +RegTestMain() +{ + InitializeTests(); + RegisterTests(); + PerformTests(); +} diff --git a/reactos/regtests/win32base/file-1.c b/reactos/regtests/win32base/file-1.c new file mode 100755 index 00000000000..bb50fa8c543 --- /dev/null +++ b/reactos/regtests/win32base/file-1.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "regtests.h" + +static int RunTest(char *Buffer) +{ + char buffer[4096]; + HANDLE file; + DWORD wrote; + int c; + + file = CreateFile("test.dat", + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + 0, + 0); + + if (file == INVALID_HANDLE_VALUE) + { + sprintf(Buffer, "Error opening file (Status %x)", GetLastError()); + return TS_FAILED; + } + + for (c = 0; c < sizeof(buffer); c++) + buffer[c] = (char)c; + + if (WriteFile( file, buffer, 4096, &wrote, NULL) == FALSE) + { + sprintf(Buffer, "Error writing file (Status %x)", GetLastError()); + return TS_FAILED; + } + + SetFilePointer(file, 0, 0, FILE_BEGIN); + + if (ReadFile( file, buffer, 4096, &wrote, NULL) == FALSE) + { + sprintf(Buffer, "Error reading file (Status %x)", GetLastError()); + return TS_FAILED; + } + for (c = 0; c < sizeof(buffer); c++) + { + if (buffer[c] != (char)c) + { + strcpy(Buffer, "Error: data read back is not what was written"); + CloseHandle(file); + return TS_FAILED; + } + } + + CloseHandle(file); + return TS_OK; +} + +int +File_1Test(int Command, char *Buffer) +{ + switch (Command) + { + case TESTCMD_RUN: + return RunTest(Buffer); + case TESTCMD_TESTNAME: + strcpy(Buffer, "File read/write"); + return TS_OK; + default: + break; + } + return TS_FAILED; +} diff --git a/reactos/regtests/win32base/win32base.def b/reactos/regtests/win32base/win32base.def new file mode 100755 index 00000000000..acb9dd17905 --- /dev/null +++ b/reactos/regtests/win32base/win32base.def @@ -0,0 +1,3 @@ +LIBRARY win32base.dll +EXPORTS +RegTestMain@0 diff --git a/reactos/regtests/win32base/win32base.edf b/reactos/regtests/win32base/win32base.edf new file mode 100755 index 00000000000..ec7a45280ad --- /dev/null +++ b/reactos/regtests/win32base/win32base.edf @@ -0,0 +1,3 @@ +LIBRARY win32base.dll +EXPORTS +RegTestMain=RegTestMain@0 diff --git a/reactos/rules.mak b/reactos/rules.mak index 8db52b399bd..9505c103efe 100644 --- a/reactos/rules.mak +++ b/reactos/rules.mak @@ -94,6 +94,7 @@ RMDIR = $(TOOLS_PATH)/rrmdir RMKDIR = $(TOOLS_PATH)/rmkdir RSYM = $(TOOLS_PATH)/rsym RTOUCH = $(TOOLS_PATH)/rtouch +REGTESTS = $(TOOLS_PATH)/regtests MC = $(TOOLS_PATH)/wmc/wmc XSLTPROC = xsltproc diff --git a/reactos/tools/Makefile b/reactos/tools/Makefile index 39f73f44b14..3136e6d085e 100644 --- a/reactos/tools/Makefile +++ b/reactos/tools/Makefile @@ -3,6 +3,7 @@ PATH_TO_TOP = .. TOOLS = \ buildno$(EXE_POSTFIX) \ depends$(EXE_POSTFIX) \ + regtests$(EXE_POSTFIX) \ rcopy$(EXE_POSTFIX) \ rdel$(EXE_POSTFIX) \ rline$(EXE_POSTFIX) \ @@ -23,6 +24,9 @@ buildno$(EXE_POSTFIX): buildno.c ../include/reactos/version.h depends$(EXE_POSTFIX): depends.c $(HOST_CC) $(CFLAGS) -o depends$(EXE_POSTFIX) depends.c +regtests$(EXE_POSTFIX): regtests.c + $(HOST_CC) $(CFLAGS) -o regtests$(EXE_POSTFIX) regtests.c + ifeq ($(HOST),mingw32-linux) rcopy$(EXE_POSTFIX): rcopy.c $(HOST_CC) $(CFLAGS) -DUNIX_PATHS rcopy.c -o rcopy$(EXE_POSTFIX) diff --git a/reactos/tools/config.mk b/reactos/tools/config.mk index d35948ec707..73b9c725a50 100644 --- a/reactos/tools/config.mk +++ b/reactos/tools/config.mk @@ -25,6 +25,10 @@ ifeq ($(ACPI), 1) CONFIG += ACPI endif +ifeq ($(SEH), 1) +CONFIG += SEH +endif + $(PATH_TO_TOP)/tools/mkconfig$(EXE_POSTFIX): $(PATH_TO_TOP)/tools/mkconfig.c $(HOST_CC) -g -o $(PATH_TO_TOP)/tools/mkconfig$(EXE_POSTFIX) $(PATH_TO_TOP)/tools/mkconfig.c diff --git a/reactos/tools/helper.mk b/reactos/tools/helper.mk index 31eb2e078de..96d9195ce3a 100644 --- a/reactos/tools/helper.mk +++ b/reactos/tools/helper.mk @@ -1,4 +1,4 @@ -# $Id: helper.mk,v 1.39 2003/07/06 23:04:19 hyperion Exp $ +# $Id: helper.mk,v 1.40 2003/07/11 18:13:57 chorns Exp $ # # Helper makefile for ReactOS modules # Variables this makefile accepts: @@ -44,6 +44,7 @@ # $TARGET_PCH = Filename of header to use to generate a PCH if supported by the compiler (optional) # $TARGET_BOOTSTRAP = Wether this file is needed to bootstrap the installation (no,yes) (optional) # $TARGET_BOOTSTRAP_NAME = Name on the installation medium (optional) +# $TARGET_GENREGTESTS = Generate regression test registrations (optional) # $WINE_MODE = Compile using WINE headers (no,yes) (optional) # $WINE_RC = Name of .rc file for WINE modules (optional) @@ -436,7 +437,6 @@ else MK_FULLRES := $(TARGET_PATH)/$(MK_RESOURCE) endif - ifeq ($(TARGET_DEFNAME),) MK_DEFBASE := $(TARGET_NAME) else @@ -540,7 +540,21 @@ $(MK_IMPLIBPATH)/$(MK_IMPLIB_FULLNAME): $(TARGET_OBJECTS) $(MK_DEFNAME) else # MK_IMPLIBONLY -all: $(MK_FULLNAME) $(MK_NOSTRIPNAME) +all: $(MK_GENREGTESTS) $(MK_FULLNAME) $(MK_NOSTRIPNAME) + + +ifeq ($(TARGET_GENREGTESTS),yes) +_regtests_phony: + $(RM) _regtests.c +.PHONY: _regtests_phony +_regtests.c: _regtests_phony + $(REGTESTS) . _regtests.c + MK_GENREGTESTS := _regtests_phony + MK_GENREGTESTS_CLEAN := _regtests.c _regtests.o +else + MK_GENREGTESTS := + MK_GENREGTESTS_CLEAN := +endif ifeq ($(MK_IMPLIB),yes) @@ -721,7 +735,7 @@ MK_CLEANDEPS := $(join $(dir $(MK_CLEANFILTERED)), $(addprefix ., $(notdir $(MK_ clean: - $(RM) *.o depend.d *.pch $(MK_BASENAME).sym $(MK_BASENAME).a $(TARGET_PATH)/$(MK_RES_BASE).coff \ - $(MK_FULLNAME) $(MK_NOSTRIPNAME) $(MK_CLEANFILES) $(MK_CLEANDEPS) $(MK_BASENAME).map \ + $(MK_FULLNAME) $(MK_NOSTRIPNAME) $(MK_CLEANFILES) $(MK_CLEANDEPS) $(MK_GENREGTESTS_CLEAN) $(MK_BASENAME).map \ junk.tmp base.tmp temp.exp \ $(TARGET_CLEAN) diff --git a/reactos/tools/regtests.c b/reactos/tools/regtests.c new file mode 100755 index 00000000000..2477e1010dc --- /dev/null +++ b/reactos/tools/regtests.c @@ -0,0 +1,355 @@ +/* + * Generate a file with test registrations from a list + * of files in a directory. + * Casper S. Hornstrup + */ + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#include +#endif +#include +#ifndef WIN32 +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif +#define DIR_SEPARATOR_CHAR '/' +#define DIR_SEPARATOR_STRING "/" +#else +#define DIR_SEPARATOR_CHAR '\\' +#define DIR_SEPARATOR_STRING "\\" +#endif + +static FILE *out; +static char *path; +static char *file; + +char* convert_path(char* origpath) +{ + char* newpath; + int i; + + newpath = strdup(origpath); + + i = 0; + while (newpath[i] != 0) + { +#ifndef WIN32 + if (newpath[i] == '\\') + { + newpath[i] = '/'; + } +#else +#ifdef WIN32 + if (newpath[i] == '/') + { + newpath[i] = '\\'; + } +#endif +#endif + i++; + } + return(newpath); +} + +static void write_line(char *line) +{ + int n_out; + char buf[200]; + + memset(buf, 0, sizeof(buf)); + strcpy(buf, line); + /* Terminate the line */ + buf[strlen(buf)] = '\r'; + buf[strlen(buf)] = '\n'; + + n_out = fwrite(&buf[0], 1, strlen(buf), out); +} + +void register_test(char *filename, int prototype) +{ + char ext[100]; + char testname[100]; + char call[100]; + char regtest[100]; + int i, j; + + strcpy(testname, filename); + + i = strlen(testname); + while (i > 0 && testname[i] != '.') + { + i--; + } + if (i > 0) + { + memset(ext, 0, sizeof(ext)); + strncpy(&ext[0], &testname[i], strlen(&testname[i])); + + if ((strncmp(ext, ".c", 2) != 0) && (strncmp(ext, ".C", 2) != 0)) + { + return; + } + + testname[i] = 0; + } + else + { + return; + } + + // Make a capital first letter and make all other letters lower case + testname[0] = toupper(testname[0]); + if (!((testname[0] >= 'A' && testname[0] <= 'Z') || + (testname[0] >= '0' && testname[0] <= '9'))) + { + testname[0] = '_'; + } + j = 1; + while (j < strlen(testname)) + { + testname[j] = tolower(testname[j]); + if (!((testname[j] >= 'a' && testname[j] <= 'z') || + (testname[j] >= '0' && testname[j] <= '9'))) + { + testname[j] = '_'; + } + j++; + } + + if (prototype) + { + sprintf(regtest, "extern int %sTest(int Command, char *Buffer);", testname); + write_line(regtest); + } + else + { + sprintf(call, "%sTest", testname); + sprintf(regtest, " AddTest((TestRoutine)%s);", call); + write_line(regtest); + } +} + +#ifdef WIN32 + +/* Win32 version */ + +static void +make_file_list (int prototype) +{ + struct _finddata_t f; + int findhandle; + char searchbuf[MAX_PATH]; + + strcpy(searchbuf, path); + strcpy(searchbuf, "*.*"); + findhandle =_findfirst(searchbuf, &f); + if (findhandle != -1) + { + do + { + if (f.attrib & _A_SUBDIR) + { + /* Skip subdirectories */ + continue; + } + + register_test(f.name, prototype); + } + while (_findnext(findhandle, &f) == 0); + _findclose(findhandle); + } +} + +#else + +/* Linux version */ +static void +make_file_list (int prototype) +{ + DIR *dirp; + struct dirent *entry; + struct stat stbuf; + char buf[MAX_PATH]; + +#ifdef HAVE_D_TYPE + dirp = opendir(path); + if (dirp != NULL) + { + while ((entry = readdir(dirp)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; // skip self and parent + + if (entry->d_type == DT_REG) // normal file + { + // Check for an absolute path + if (path[0] == DIR_SEPARATOR_CHAR) + { + strcpy(buf, path); + strcat(buf, DIR_SEPARATOR_STRING); + strcat(buf, entry->d_name); + } + else + { + getcwd(buf, sizeof(buf)); + strcat(buf, DIR_SEPARATOR_STRING); + strcat(buf, path); + strcat(buf, entry->d_name); + } + + if (stat(buf, &stbuf) == -1) + { + printf("Can't access '%s' (%s)\n", buf, strerror(errno)); + return; + } + + if (S_ISDIR(stbuf.st_mode)) + { + /* Skip subdirectories */ + continue; + } + + register_test(entry->d_name, prototype); + } + } + closedir(dirp); + } + else + { + printf("Can't open %s\n", path); + return; + } + +#else + + dirp = opendir(path); + if (dirp != NULL) + { + while ((entry = readdir(dirp)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; // skip self and parent + + // Check for an absolute path + if (path[0] == DIR_SEPARATOR_CHAR) + { + strcpy(buf, path); + strcat(buf, DIR_SEPARATOR_STRING); + strcat(buf, entry->d_name); + } + else + { + getcwd(buf, sizeof(buf)); + strcat(buf, DIR_SEPARATOR_STRING); + strcat(buf, path); + strcat(buf, entry->d_name); + } + + if (stat(buf, &stbuf) == -1) + { + printf("Can't access '%s' (%s)\n", buf, strerror(errno)); + return; + } + + if (S_ISDIR(stbuf.st_mode)) + { + /* Skip subdirectories */ + continue; + } + + register_test(entry->d_name, prototype); + } + closedir(dirp); + } + else + { + printf("Can't open %s\n", path); + return; + } + +#endif +} + +#endif + +static char HELP[] = + "REGTESTS path file\n" + "\n" + " path Path to files\n" + " file File to create\n"; + +int main(int argc, char **argv) +{ + char buf[MAX_PATH]; + int i; + + if (argc < 2) + { + puts(HELP); + return 1; + } + + + strcpy(buf, convert_path(argv[1])); + if (buf[strlen(buf)] != DIR_SEPARATOR_CHAR) + { + int i = strlen(buf); + buf[strlen(buf)] = DIR_SEPARATOR_CHAR; + buf[i + 1] = 0; + } + path = buf; + if (path[0] == 0) + { + printf("Missing path\n"); + return 1; + } + + file = convert_path(argv[2]); + if (file[0] == 0) + { + printf("Missing file\n"); + return 1; + } + + out = fopen(file, "wb"); + if (out == NULL) + { + perror("Cannot open output file"); + return 1; + } + + write_line("/* This file is autogenerated. */"); + write_line(""); + write_line("typedef int (*TestRoutine)(int Command, char *Buffer);"); + write_line(""); + + make_file_list(1); + + write_line(""); + write_line("extern void AddTest(TestRoutine Routine);"); + write_line(""); + write_line("void RegisterTests()"); + write_line("{"); + + make_file_list(0); + + write_line("}"); + + fclose(out); + + return 0; +} + +/* EOF */